diff --git a/.gitignore b/.gitignore index b1a6abf..6a1af0c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,11 @@ npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* + +# Claude Code temporary files +tmpclaude-* +nul +.claude/ # Ignore Visual Studio files .vs/ *.vsidx @@ -164,6 +169,22 @@ dist/* !dist/providers/** !dist/types/ !dist/types/** +!dist/mcp/ +!dist/mcp/** # ArchDoc configuration (contains API keys) .archdoc.config.json + +# SQLite database (local analysis history) +pr-agent.db +*.db + +# Local MCP configuration override (optional - for user-specific settings) +# Note: The project .mcp.json is tracked for team-wide configuration +.mcp.local.json +*.db + +# Temporary test output and analysis files +*-output.txt +*-output-*.txt +*-snapshot.txt diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..aed94aa --- /dev/null +++ b/.mcp.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://github.com/modelcontextprotocol/specification/blob/main/schema/mcp.schema.json", + "$comment": "===== PR Agent: CLI Tool + MCP Server =====", + "$comment2": "This repository is primarily a CLI tool (pr-agent) for analyzing pull requests.", + "$comment3": "It also includes an MCP server (src/mcp/) that exposes the same functionality via MCP.", + "$comment4": "", + "$comment5": "Setup: npm install --legacy-peer-deps && npm run build", + "$comment6": "", + "$comment7": "Available MCP Tools (see server.json for full schemas):", + "$comment8": " • analyze - Analyze PR/branch changes with diff parsing, risk detection, complexity scoring, Jira ticket extraction", + "$comment9": " • dashboard - Start web dashboard to view analysis history, code quality trends, and ROI metrics", + "$comment10": "", + "$comment11": "The MCP server imports and reuses the CLI's PRAnalyzerAgent and analysis tools.", + "$comment12": "", + "$comment13": "===== Required MCP Servers for Full Functionality =====", + "$comment14": "The Atlassian Rovo MCP Server provides Jira/Confluence access via OAuth (requires Node.js 18+)", + "$comment15": "GitHub MCP server enables repository and PR management", + "$comment16": "The PR Agent extracts Jira ticket IDs, then uses the Atlassian MCP server to fetch ticket details.", + "mcpServers": { + "pr-agent": { + "command": "npm", + "args": ["run", "mcp"], + "env": { + "NODE_ENV": "development" + } + }, + "atlassian": { + "command": "cmd", + "args": ["/c", "npx", "-y", "mcp-remote", "https://mcp.atlassian.com/v1/mcp"] + }, + "github": { + "command": "cmd", + "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-github"] + } + } +} diff --git a/.pr-analyzer.yml b/.pr-analyzer.yml index 99bdc30..1b7687a 100644 --- a/.pr-analyzer.yml +++ b/.pr-analyzer.yml @@ -1,28 +1,46 @@ # PR Analyzer Configuration -# This file configures the AI-powered PR analysis +# This file documents available configuration options for the PR Analyzer +# GitHub Action reads from environment variables, CLI uses .pragent.config.json # Analysis settings analysis: # Maximum complexity level to flag (1-5) max_complexity: 4 - + # Whether to include potential risks in analysis include_risks: true - + # Whether to include complexity rating include_complexity: true # AI model settings ai: # Model to use for analysis - model: "claude-3-5-sonnet-20241022" - + model: "claude-sonnet-4-5-20250929" + # Maximum tokens for response - max_tokens: 1500 - + max_tokens: 50000 + # Temperature for creativity (0.0-1.0) temperature: 0.2 +# Peer Review settings (CLI only - requires .pragent.config.json) +peerReview: + # Enable peer review against Jira tickets + enabled: false + + # Analyze acceptance criteria compliance + analyzeAcceptanceCriteria: true + + # Rate ticket quality (completeness, clarity) + rateTicketQuality: true + + # Generate test suggestions based on AC + generateTestSuggestions: true + + # Check for scope creep (changes outside ticket scope) + checkScopeCreep: true + # File patterns to include/exclude files: # Include these file patterns @@ -35,7 +53,11 @@ files: - "**/*.java" - "**/*.go" - "**/*.rs" - + - "**/*.cs" + - "**/*.cpp" + - "**/*.c" + - "**/*.h" + # Exclude these file patterns exclude: - "**/*.test.*" diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 0000000..9a1e2cb --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,31 @@ +{ + "$comment": "MCP Server Configuration for PR Agent (CLI Tool + MCP Server)", + "$comment2": "PR Agent is primarily a CLI tool for PR analysis that also exposes MCP server functionality", + "$comment3": "The MCP server (src/mcp/) imports and reuses the CLI's core analysis engine", + "$comment4": "After 'npm install && npm run build', the server provides these tools:", + "$comment5": " - analyze: Parse git diff, detect risks, calculate complexity, extract Jira tickets", + "$comment6": " - dashboard: Start web dashboard for viewing analysis history and metrics", + "$comment7": "", + "$comment8": "For full Jira integration, also install @modelcontextprotocol/server-atlassian", + "$comment9": "For GitHub integration, also install @modelcontextprotocol/server-github", + "servers": { + "pr-agent": { + "type": "stdio", + "command": "npm", + "args": ["run", "mcp"], + "cwd": "${workspaceFolder}", + "description": "PR Agent MCP Server - AI-powered PR analysis (analyze, dashboard)" + }, + "atlassian": { + "type": "http", + "url": "https://mcp.atlassian.com/v1/mcp", + "description": "Official Atlassian Rovo MCP Server - Jira and Confluence Cloud access via OAuth" + }, + "github": { + "type": "stdio", + "command": "cmd", + "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-github"], + "description": "GitHub MCP Server - Repository and PR management" + } + } +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..96c5d6b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,94 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +PR Agent is an AI-powered pull request analyzer available as both a CLI tool and a GitHub Action. It analyzes code changes using multiple AI providers (Anthropic Claude, OpenAI GPT, Google Gemini) and provides summaries, risk detection, complexity scoring, and architecture-aware recommendations. + +## Build & Development Commands + +```bash +# Install dependencies (--legacy-peer-deps required for LangChain peer dependency conflicts) +npm install --legacy-peer-deps + +# Build everything (TypeScript + GitHub Action bundle) +npm run build + +# Build TypeScript only +npm run build:tsc + +# Build GitHub Action only (uses @vercel/ncc) +npm run build:action + +# Clean and rebuild +npm run build:clean + +# Run tests +npm test +npm test -- --watch # Watch mode +npm test -- --coverage # With coverage + +# Run single test file +npm test -- tests/config-loader.test.ts + +# Development mode (no build needed) +npm run dev + +# Run CLI from built dist +npm run cli +``` + +## Architecture + +The project follows a modular monolith pattern with four layers: + +### Entry Points +- `src/cli/index.ts` - CLI entry point using Commander.js +- `src/action.ts` - GitHub Action entry point +- `src/index.ts` - Probot app integration + +### Core Analysis Engine +- `src/agents/pr-analyzer-agent.ts` - Main LangChain-based analysis workflow +- `src/agents/base-pr-agent-workflow.ts` - LangGraph workflow orchestration + +### AI Provider Layer +- `src/providers/` - Provider implementations (Anthropic, OpenAI, Google) +- `src/providers/provider.factory.ts` - Factory pattern for instantiation +- `src/providers/provider.interface.ts` - Common interface all providers implement + +### Tools & Utilities +- `src/tools/pr-analysis-tools.ts` - Diff parsing and analysis tools +- `src/utils/arch-docs-parser.ts` - Parse `.arch-docs` documentation folder +- `src/utils/arch-docs-rag.ts` - RAG (Retrieval-Augmented Generation) for architecture context +- `src/utils/branch-resolver.ts` - Git branch detection and resolution +- `src/cli/utils/config-loader.ts` - Configuration file management + +### Data Flow +``` +User Input → CLI/Action Interface → Config Loader → PRAnalyzerAgent + → Parse Diff → Load Architecture Docs (optional) → Build RAG Context + → Provider Factory → AI Provider → Structured Analysis Results + → Format Output (CLI terminal or GitHub PR comment) +``` + +## Key Configuration Files + +- `.pragent.config.json` - User configuration (AI provider, model, API keys, analysis settings) +- `.pr-analyzer.yml` - GitHub Action configuration +- `action.yml` - GitHub Action manifest + +## Technology Stack + +- **Framework**: TypeScript/Node.js (ES Modules), requires Node.js >=18.0.0 +- **AI Orchestration**: LangChain v1.x with LangGraph for workflow management +- **CLI Framework**: Commander.js with Inquirer for interactive prompts +- **Testing**: Jest with ts-jest +- **Action Bundling**: @vercel/ncc bundles the GitHub Action into a single file + +## Important Notes + +- Large diffs (>50KB) automatically use agent-based chunking (configurable via `analysis.agentThreshold`) +- The GitHub Action bundle in `dist/` must be committed after changes to action code +- Environment variables `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or `GOOGLE_API_KEY` can be used instead of config file +- Default branch detection uses: config file → GitHub API → git commands → fallback to `origin/main` diff --git a/FULL-LLM-AGNOSTIC-REFACTORING.md b/FULL-LLM-AGNOSTIC-REFACTORING.md new file mode 100644 index 0000000..c7f9d29 --- /dev/null +++ b/FULL-LLM-AGNOSTIC-REFACTORING.md @@ -0,0 +1,473 @@ +# Full LLM-Agnostic Refactoring Plan + +## Goal +Make ALL AI analysis work without API keys in MCP mode while preserving 100% CLI functionality. + +## Problem +Currently, the MCP server uses StubChatModel which returns empty responses, causing: +- Empty/zero analysis results +- No data in dashboard +- Poor user experience + +Only peer review was refactored to be LLM-agnostic. The main PR analysis workflow still requires API keys. + +## Solution +Apply the same two-mode architecture to **ALL** LLM-based analysis: + +### Mode 1: EXECUTE (CLI) +- Input: LLM instance with API key +- Process: Build prompts AND execute them via LLM +- Output: Analyzed results (summaries, risks, complexity, recommendations) + +### Mode 2: PROMPT_ONLY (MCP) +- Input: No LLM needed (no API keys) +- Process: Build prompts but DON'T execute +- Output: Structured prompts for calling LLM to execute + +## Current LLM Usage Points + +### 1. BasePRAgentWorkflow (4 LLM invocations) +**File:** `src/agents/base-pr-agent-workflow.ts` + +#### a) analyzeFileNode() - Line ~604 +```typescript +const response = await this.model.invoke(fileDetailsPrompt); +``` +**Purpose:** Analyzes individual files for changes, patterns, and impact +**Output:** FileAnalysis with summary, changes, risks, complexity + +#### b) detectRisksNode() - Line ~785 +```typescript +const response = await this.model.invoke(riskPrompt); +``` +**Purpose:** Detects security/quality risks across all files +**Output:** Array of Fix objects with severity, file, comment + +#### c) generateSummaryNode() - Line ~1019 +```typescript +const response = await this.model.invoke(summaryPrompt); +``` +**Purpose:** Generates overall PR summary +**Output:** String summary (3-5 paragraphs) + +#### d) selfRefineNode() - Line ~1133 +```typescript +const response = await this.model.invoke(refinementPrompt); +``` +**Purpose:** Provides improvement recommendations +**Output:** Array of recommendation strings + +### 2. JiraSubAgent (3 LLM invocations) +**File:** `src/agents/jira-sub-agent.ts` + +✅ **ALREADY REFACTORED** in previous work: +- Ticket quality rating +- Acceptance criteria validation +- Peer review analysis + +### 3. Unnecessary Classes +**Files to REMOVE:** +- `src/mcp/stub-chat-model.ts` - Returns empty responses, no longer needed +- `src/mcp/mcp-chat-model.ts` - May not be needed with prompt approach + +## Implementation Plan + +### Phase 1: Core Type Definitions + +#### 1.1 Create Execution Mode Enum (Shared) +```typescript +// src/types/agent.types.ts +export enum AnalysisMode { + EXECUTE = 'execute', // CLI: Execute prompts with API key + PROMPT_ONLY = 'prompt_only' // MCP: Return prompts for calling LLM +} +``` + +#### 1.2 Create Prompt Structures +```typescript +// src/types/agent.types.ts +export interface AnalysisPrompt { + step: 'fileAnalysis' | 'riskDetection' | 'summaryGeneration' | 'selfRefinement'; + prompt: string; // The filled-in prompt template + context?: Record; // Any additional context needed + instructions: string; // How to execute this prompt +} + +export interface PromptOnlyResult { + mode: 'prompt_only'; + context: AgentContext; // All input data + prompts: AnalysisPrompt[]; // Prompts for calling LLM + instructions: string; // How to execute all prompts +} + +// Extend existing AgentResult +export type AgentResultOrPrompts = AgentResult | PromptOnlyResult; +``` + +### Phase 2: Refactor BasePRAgentWorkflow + +#### 2.1 Update Constructor +```typescript +export abstract class BasePRAgentWorkflow { + protected model?: BaseChatModel; // Now optional! + protected mode: AnalysisMode; + + constructor(mode: AnalysisMode = AnalysisMode.EXECUTE, model?: BaseChatModel) { + this.mode = mode; + this.model = model; + + if (mode === AnalysisMode.EXECUTE && !model) { + throw new Error('BasePRAgentWorkflow: LLM is required when mode is EXECUTE'); + } + + // ... rest of constructor + } +} +``` + +#### 2.2 Add Main Routing Method +```typescript +async analyze( + diff: string, + title?: string, + mode?: AnalysisOptions, + options?: ExecutionOptions +): Promise { + if (this.mode === AnalysisMode.PROMPT_ONLY) { + return this.buildAllPrompts(diff, title, mode, options); + } else { + return this.executeAnalysis(diff, title, mode, options); + } +} +``` + +#### 2.3 Create Prompt Builder Methods +```typescript +private buildAllPrompts( + diff: string, + title?: string, + mode?: AnalysisOptions, + options?: ExecutionOptions +): PromptOnlyResult { + const files = parseDiff(diff); + const context: AgentContext = { + diff, + title, + files, + // ... other context + }; + + const prompts: AnalysisPrompt[] = []; + + // Build all 4 prompts + files.forEach(file => { + prompts.push(this.buildFileAnalysisPrompt(file, context)); + }); + prompts.push(this.buildRiskDetectionPrompt(files, context)); + prompts.push(this.buildSummaryPrompt(files, context)); + prompts.push(this.buildRefinementPrompt(files, context)); + + return { + mode: 'prompt_only', + context, + prompts, + instructions: 'Execute these prompts sequentially to complete PR analysis...' + }; +} + +private buildFileAnalysisPrompt(file: DiffFile, context: AgentContext): AnalysisPrompt { + // Extract existing prompt logic from analyzeFileNode + const prompt = `You are analyzing a code change in a pull request... +${file.path} +${file.diff} +...`; + + return { + step: 'fileAnalysis', + prompt, + context: { file: file.path }, + instructions: 'Analyze this file and return structured FileAnalysis JSON' + }; +} + +private buildRiskDetectionPrompt(files: DiffFile[], context: AgentContext): AnalysisPrompt { + // Extract existing prompt logic from detectRisksNode + const prompt = `You are a security and code quality expert...`; + + return { + step: 'riskDetection', + prompt, + context: { fileCount: files.length }, + instructions: 'Detect risks and return array of Fix objects' + }; +} + +private buildSummaryPrompt(files: DiffFile[], context: AgentContext): AnalysisPrompt { + // Extract existing prompt logic from generateSummaryNode + const prompt = `Generate a comprehensive PR summary...`; + + return { + step: 'summaryGeneration', + prompt, + context: {}, + instructions: 'Generate detailed PR summary (3-5 paragraphs)' + }; +} + +private buildRefinementPrompt(files: DiffFile[], context: AgentContext): AnalysisPrompt { + // Extract existing prompt logic from selfRefineNode + const prompt = `Review the analysis and suggest improvements...`; + + return { + step: 'selfRefinement', + prompt, + context: {}, + instructions: 'Provide 3-5 actionable recommendations' + }; +} +``` + +#### 2.4 Rename/Update Execution Methods +```typescript +// Rename execute() to executeAnalysis() +private async executeAnalysis( + diff: string, + title?: string, + mode?: AnalysisOptions, + options?: ExecutionOptions +): Promise { + // Original execute() logic - UNCHANGED + // Just add LLM guards in each node +} + +// Add LLM guards to all invoke methods +private async analyzeFileNode(state: typeof PRAgentState.State) { + if (!this.model) { + throw new Error('LLM is required for file analysis in EXECUTE mode'); + } + + // ... existing logic + const response = await this.model.invoke(fileDetailsPrompt); + // ... +} + +// Same for detectRisksNode, generateSummaryNode, selfRefineNode +``` + +### Phase 3: Update PRAnalyzerAgent + +```typescript +export class PRAnalyzerAgent extends BasePRAgentWorkflow { + constructor(options: PRAnalyzerOptions = {}) { + // Determine mode + const mode = options.mode || AnalysisMode.EXECUTE; + + let model: BaseChatModel | undefined; + + // Only create model in EXECUTE mode + if (mode === AnalysisMode.EXECUTE) { + if (options.chatModel) { + model = options.chatModel; + } else { + model = ProviderFactory.createChatModel({ + provider: options.provider || 'anthropic', + apiKey: options.apiKey, + model: options.model, + temperature: options.temperature ?? 0.2, + maxTokens: options.maxTokens ?? 4000, + }); + } + } + + super(mode, model); + } +} + +export interface PRAnalyzerOptions extends ProviderOptions { + mode?: AnalysisMode; + chatModel?: BaseChatModel; +} +``` + +### Phase 4: Update CLI (analyze.command.ts) + +```typescript +// Add mode to options (always EXECUTE for CLI) +const agent = new PRAnalyzerAgent({ + provider: providerOptions.provider, + apiKey: providerOptions.apiKey, + model: providerOptions.model, + temperature: 0.2, + maxTokens: 4000, + mode: AnalysisMode.EXECUTE, // <-- CLI always executes +}); + +const result = await agent.analyze(diff, title, analysisMode, options); + +// Type guard - CLI should never get PromptOnlyResult +if (result.mode === 'prompt_only') { + throw new Error('Unexpected prompt-only result in CLI'); +} + +// Use result as AgentResult +const agentResult = result as AgentResult; +``` + +### Phase 5: Update MCP Server + +```typescript +// Use PROMPT_ONLY mode - no LLM, no API keys +const agent = new PRAnalyzerAgent({ + mode: AnalysisMode.PROMPT_ONLY, // <-- MCP returns prompts +}); + +const result = await agent.analyze(diff, title, analysisMode, options); + +// Type guard - check mode +if (result.mode === 'prompt_only') { + // Format prompts for calling LLM + return { + content: [{ + type: 'text', + text: formatAllPromptsForLLM(result) + }] + }; +} else { + // Should not happen in MCP with PROMPT_ONLY mode + throw new Error('Expected prompt-only result'); +} +``` + +#### 5.1 Create Prompt Formatter +```typescript +function formatAllPromptsForLLM(result: PromptOnlyResult): string { + const lines: string[] = []; + + lines.push('🤖 PR Agent Analysis Prompts (LLM-Agnostic Mode)'); + lines.push(''); + lines.push('Execute the following prompts sequentially:'); + lines.push(''); + + result.prompts.forEach((prompt, i) => { + const stepName = { + 'fileAnalysis': '1️⃣ File Analysis', + 'riskDetection': '2️⃣ Risk Detection', + 'summaryGeneration': '3️⃣ Summary Generation', + 'selfRefinement': '4️⃣ Self Refinement' + }[prompt.step]; + + lines.push(`${stepName}`); + lines.push(''); + lines.push('```'); + lines.push(prompt.prompt); + lines.push('```'); + lines.push(''); + lines.push(`Instructions: ${prompt.instructions}`); + lines.push(''); + }); + + return lines.join('\n'); +} +``` + +### Phase 6: Remove Unnecessary Classes + +#### 6.1 Delete StubChatModel +```bash +rm src/mcp/stub-chat-model.ts +``` + +#### 6.2 Delete MCPChatModel +```bash +rm src/mcp/mcp-chat-model.ts +``` + +#### 6.3 Update Imports +Remove all imports of StubChatModel and MCPChatModel from: +- `src/mcp/server.ts` +- Any test files + +### Phase 7: Update Type Exports + +```typescript +// src/types/agent.types.ts +export { + AnalysisMode, + AnalysisPrompt, + PromptOnlyResult, + AgentResultOrPrompts, + // ... existing exports +}; + +// src/agents/index.ts +export { + PRAnalyzerAgent, + BasePRAgentWorkflow, + AnalysisMode, + // ... existing exports +}; +``` + +## Migration Steps + +1. ✅ Create new branch (already done: `feat/llm-agnostic-peer-review`) +2. ✅ Peer review refactoring complete +3. Add AnalysisMode enum and types to `agent.types.ts` +4. Refactor `BasePRAgentWorkflow`: + - Add mode parameter to constructor + - Make model optional + - Extract all 4 prompt building methods + - Add buildAllPrompts() method + - Rename execute() to executeAnalysis() + - Add LLM guards to all invoke calls +5. Update `PRAnalyzerAgent`: + - Add mode to constructor options + - Conditionally create model based on mode +6. Update CLI (`analyze.command.ts`): + - Pass AnalysisMode.EXECUTE + - Add type guard for result +7. Update MCP server (`server.ts`): + - Pass AnalysisMode.PROMPT_ONLY + - Add formatAllPromptsForLLM() + - Remove StubChatModel usage +8. Delete unnecessary classes: + - `src/mcp/stub-chat-model.ts` + - `src/mcp/mcp-chat-model.ts` +9. Update imports and exports +10. Build and test CLI workflow +11. Build and test MCP workflow + +## Testing Checklist + +### CLI (EXECUTE mode) +- [ ] File analysis works +- [ ] Risk detection works +- [ ] Summary generation works +- [ ] Self-refinement works +- [ ] Peer review works (already tested) +- [ ] Database saves correctly +- [ ] Output format unchanged +- [ ] All analysis modes work (summary, risks, complexity, full) + +### MCP (PROMPT_ONLY mode) +- [ ] Returns structured prompts for all analysis steps +- [ ] Includes all context data +- [ ] No LLM calls attempted +- [ ] Works without API keys +- [ ] Peer review prompts included +- [ ] Dashboard can display results after calling LLM executes prompts + +## Benefits + +1. **MCP server works without API keys** - Uses calling LLM (Claude Code, Cursor, etc.) +2. **CLI unchanged** - Still uses API keys, full backward compatibility +3. **Consistent architecture** - Same pattern for all AI analysis +4. **Cleaner codebase** - Remove StubChatModel hack +5. **Future-proof** - When MCP sampling arrives, easy to integrate + +## Rollback Plan + +If issues arise: +1. Revert branch to main +2. All CLI functionality unchanged on main +3. MCP server will have stub data (current state) diff --git a/MCP-LOCAL-SETUP.md b/MCP-LOCAL-SETUP.md new file mode 100644 index 0000000..4bdc531 --- /dev/null +++ b/MCP-LOCAL-SETUP.md @@ -0,0 +1,295 @@ +# MCP Server - Local Development Setup + +> **Important Architecture Note**: PR Agent is primarily a **CLI tool** for analyzing pull requests. The MCP server (located in `src/mcp/`) is an additional component that exposes the same analysis functionality via the Model Context Protocol. The MCP server imports and reuses the CLI's core `PRAnalyzerAgent` and analysis tools. + +This guide helps you set up and demo the PR Agent MCP server when working with this repository. + +## Project Structure + +``` +pr-agent/ # Primary: CLI tool for PR analysis +├── src/ +│ ├── cli/ # CLI commands (pr-agent) +│ ├── agents/ # Core analysis engine (PRAnalyzerAgent) +│ ├── tools/ # Analysis tools (diff parsing, risk detection) +│ └── mcp/ # MCP server component +│ └── server.ts # MCP server that imports CLI functionality +├── dist/ +│ ├── cli/index.js # Built CLI (bin: pr-agent) +│ └── mcp/server.js # Built MCP server (bin: pr-agent-mcp) +├── .mcp.json # Project-wide MCP config (Claude Code, Cursor, etc.) +├── .vscode/mcp.json # VS Code + GitHub Copilot MCP config +└── server.json # MCP server manifest (tool schemas) +``` + +## MCP Server Tools + +The PR Agent MCP server provides two tools (see `server.json` for full schemas): + +1. **`analyze`** - Analyze PR/branch changes + - Parses git diff + - Detects security risks, code quality issues + - Calculates complexity scores + - Extracts Jira ticket references + - Includes architecture documentation context + +2. **`dashboard`** - Start web dashboard + - View analysis history + - Code quality trends + - ROI metrics + +## Required MCP Servers for Full Functionality + +The PR Agent MCP server works best when combined with these official MCP servers: + +### 1. Atlassian MCP Server (For Jira Integration) +**What it does**: The PR Agent extracts Jira ticket IDs (e.g., `PROJ-123`) from PR titles, branch names, and commits. The Atlassian MCP server then fetches the actual ticket details, acceptance criteria, and requirements. + +**Installation**: Already configured in `.mcp.json`. Claude Code will prompt you to enable it on first use. + +**Configuration**: You'll need Jira credentials. See [Atlassian MCP Server docs](https://github.com/modelcontextprotocol/servers/tree/main/src/atlassian). + +### 2. GitHub MCP Server (For Repository Management) +**What it does**: Provides GitHub API access for repository management, PR operations, and more. + +**Installation**: Already configured in `.mcp.json`. Claude Code will prompt you to enable it on first use. + +**Configuration**: Requires GitHub authentication. See [GitHub MCP Server docs](https://github.com/modelcontextprotocol/servers/tree/main/src/github). + +### How They Work Together + +``` +User: "Analyze my PR changes" + ↓ +PR Agent MCP Server: + - Parses git diff + - Detects risks and complexity + - Extracts "PROJ-123" from branch name + - Returns analysis with ticket ID + ↓ +Claude Code (via Atlassian MCP): + - Fetches PROJ-123 details from Jira + - Validates PR against acceptance criteria + - Provides comprehensive review +``` + +## Quick Start (For Colleagues & Contributors) + +### 1. Clone and Build + +```bash +git clone https://github.com/techdebtgpt/pr-agent.git +cd pr-agent +npm install --legacy-peer-deps +npm run build +``` + +### 2. Configure Your MCP Client + +#### Option A: Claude Code (Recommended) + +1. Find your Claude Code settings file: + - **Windows**: `%USERPROFILE%\.claude\settings.json` + - **macOS/Linux**: `~/.claude/settings.json` + +2. Add the MCP server configuration: + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "node", + "args": ["C:/Repos/peer-agent/dist/mcp/server.js"] + } + } +} +``` + +**Important**: Replace `C:/Repos/peer-agent` with the absolute path to your cloned repository. + +3. Restart Claude Code + +#### Option B: Cursor / Windsurf / Other MCP Clients + +Add to your MCP configuration file (location varies by client): + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "node", + "args": ["/absolute/path/to/pr-agent/dist/mcp/server.js"] + } + } +} +``` + +### 3. Verify Installation + +In your MCP client (e.g., Claude Code), you should now see the PR Agent tools available: +- `analyze` - Analyze PR/branch changes +- `dashboard` - Start the web dashboard + +### 4. Test It Out + +Open a git repository with changes and ask your AI assistant: +``` +Analyze my current branch changes +``` + +The MCP server will parse the diff, detect risks, calculate complexity, and return a formatted analysis. + +## Project Structure + +``` +pr-agent/ +├── src/ +│ └── mcp/ +│ ├── server.ts # MCP server implementation +│ └── stub-chat-model.ts # Stub model for LLM-agnostic operation +├── dist/ +│ └── mcp/ +│ └── server.js # Built MCP server (run this) +├── .mcp.json.example # Example MCP config (copy and customize) +├── server.json # MCP server manifest (for publishing) +└── docs/ + └── MCP-SERVER.md # Full MCP documentation +``` + +## Configuration File (.pragent.config.json) + +The MCP server uses the same configuration as the CLI. Create `.pragent.config.json` in your project root: + +```json +{ + "git": { + "defaultBranch": "origin/main" + }, + "analysis": { + "language": "typescript", + "framework": "react", + "enableStaticAnalysis": true + }, + "peerReview": { + "enabled": false + } +} +``` + +> **Note**: The MCP server is LLM-agnostic, so AI provider settings (`ai.provider`, `apiKeys`) are ignored. + +## Available Tools + +### analyze +Analyzes PR/branch changes with comprehensive diff parsing, risk detection, and complexity scoring. + +**Example prompts:** +- "Analyze my current branch changes" +- "Analyze staged changes" +- "Analyze changes against origin/develop" + +### dashboard +Starts a local web dashboard for viewing analysis history and metrics. + +**Example prompts:** +- "Start the PR Agent dashboard" +- "Start the dashboard on port 3001" + +## Troubleshooting + +### MCP Server Not Starting + +1. **Check the build**: Ensure `npm run build` completed successfully +2. **Test manually**: Run `node dist/mcp/server.js` and check for errors +3. **Check Node version**: Requires Node.js >=18.0.0 + +```bash +# Test manually +node dist/mcp/server.js + +# Check Node version +node --version +``` + +### Config Path Issues + +Make sure you use the **absolute path** to the repository in your MCP configuration: + +**Wrong** (relative path): +```json +"args": ["./dist/mcp/server.js"] +``` + +**Correct** (absolute path): +```json +"args": ["C:/Repos/peer-agent/dist/mcp/server.js"] +``` + +### Changes Not Being Built + +After making changes to the MCP server code, rebuild: + +```bash +npm run build +``` + +Then restart your MCP client (e.g., Claude Code). + +### Database Location + +Analysis data is stored in `pr-agent.db` (SQLite) in the working directory where the MCP server runs. You can view this data using the dashboard. + +## Development Workflow + +1. **Make changes** to `src/mcp/server.ts` +2. **Rebuild**: `npm run build` +3. **Restart** your MCP client +4. **Test** using an AI prompt + +## Demo for Team Members + +To demo the MCP server to your team: + +1. **Build the project** (see Quick Start above) +2. **Configure Claude Code** with the local MCP server +3. **Open a git repository** with some changes +4. **Ask Claude Code**: "Analyze my current branch changes" +5. **Show the dashboard**: "Start the PR Agent dashboard" + +The analysis will show: +- Summary of changed files and lines +- Complexity score (1-5) +- Detected risks (security, quality, breaking changes) +- File-by-file breakdown +- Linked Jira tickets (if configured) +- Architecture documentation context (if `.arch-docs` exists) + +## Publishing (For Maintainers) + +### To npm + +```bash +npm login +npm publish --access public +``` + +### To Smithery + +1. Connect repository at https://smithery.ai +2. Start deployment from dashboard +3. Server becomes discoverable + +See [docs/MCP-SERVER.md](docs/MCP-SERVER.md) for full publishing details. + +## Additional Resources + +- [Full MCP Documentation](docs/MCP-SERVER.md) +- [CLI Documentation](README.md) +- [CLAUDE.md](CLAUDE.md) - Project overview for Claude Code +- [Model Context Protocol](https://modelcontextprotocol.io/) + +## Support + +For issues or questions: +- Open an issue: https://github.com/techdebtgpt/pr-agent/issues +- Check existing docs: [docs/MCP-SERVER.md](docs/MCP-SERVER.md) diff --git a/README.md b/README.md index 2d8bfca..4232a38 100644 --- a/README.md +++ b/README.md @@ -12,18 +12,21 @@ PR Agent analyzes your code changes and provides: - **Complexity Rating**: A 1-5 scale rating of complexity with file-level breakdown - **Actionable Insights**: Specific recommendations based on your codebase - **Architecture-Aware Analysis**: Leverages your `.arch-docs` for context-aware reviews +- **Peer Review Integration**: Validates PRs against linked Jira tickets and acceptance criteria - **Static Analysis**: Semgrep integration for security vulnerabilities and code quality issues ## Features -✨ **Intelligent Agent Mode** - Automatically handles large diffs without chunking -🏗️ **Architecture Documentation Integration** - Uses `.arch-docs` for smarter analysis -🔬 **Static Analysis Integration** - Semgrep-powered security and code quality scanning -🔌 **Multiple AI Providers** - Anthropic Claude, OpenAI GPT, Google Gemini -🖥️ **CLI & GitHub Action** - Use locally or in CI/CD pipelines -📊 **File-Level Analysis** - Individual risk and complexity scores per file -🌐 **Language-Aware** - Supports TypeScript, JavaScript, Python, Java, Go, Rust, and more -⚙️ **Configurable** - Customize models, providers, and analysis modes +✨ **Intelligent Agent Mode** - Automatically handles large diffs without chunking +🏗️ **Architecture Documentation Integration** - Uses `.arch-docs` for smarter analysis +🔬 **Static Analysis Integration** - Semgrep-powered security and code quality scanning +🔌 **Multiple AI Providers** - Anthropic Claude, OpenAI GPT, Google Gemini, Zhipu AI +🖥️ **CLI & GitHub Action** - Use locally or in CI/CD pipelines +🔗 **MCP Server** - LLM-agnostic integration with Claude Code, Cursor, Cline, and more +📊 **File-Level Analysis** - Individual risk and complexity scores per file +🎫 **Peer Review Integration** - Validates against Jira tickets and acceptance criteria +🌐 **Language-Aware** - Supports TypeScript, JavaScript, Python, Java, Go, Rust, and more +⚙️ **Configurable** - Customize models, providers, and analysis modes 🎨 **Unified Output Format** - Semgrep and AI findings use consistent formatting, sorted by severity ## Quick Reference @@ -53,12 +56,16 @@ pr-agent help # Show help - [Installation](#installation) - [CLI Installation](#cli-installation) - [GitHub Action Setup](#github-action-setup) + - [MCP Server Installation](#mcp-server-installation) - [CLI Usage](#cli-usage) - [Quick Start](#quick-start) - [Analyze Command](#analyze-command) - [Configuration](#configuration) +- [UI Dashboard](#ui-dashboard) +- [MCP Server](#mcp-server) - [Architecture Documentation Integration](#architecture-documentation-integration) - [Static Analysis Integration](#static-analysis-integration) +- [Peer Review Integration](#peer-review-integration) - [GitHub Action Usage](#github-action-usage) - [Supported AI Models](#supported-ai-models) - [Common Use Cases](#common-use-cases) @@ -75,6 +82,7 @@ Before using PR Agent, you'll need: - **Anthropic Claude**: Sign up at [Anthropic Console](https://console.anthropic.com/) (Recommended) - **OpenAI GPT**: Get your key from [OpenAI Platform](https://platform.openai.com/) - **Google Gemini**: Get your key from [Google AI Studio](https://makersuite.google.com/) + - **Zhipu AI**: Get your key from [Zhipu AI Platform](https://open.bigmodel.cn/) (Anthropic-compatible API) 2. **For GitHub Action**: Repository with permissions to add workflows and secrets @@ -101,6 +109,23 @@ pr-agent --version pr-agent help ``` +### MCP Server Installation + +> **Note**: PR Agent is primarily a CLI tool. The MCP server (`src/mcp/`) is an additional component that exposes the same analysis functionality via the Model Context Protocol for use with Claude Code, Cursor, Cline, and Windsurf. + +The MCP server is **LLM-agnostic** - it uses the calling tool's AI instead of requiring API keys. It provides two tools: `analyze` (PR analysis) and `dashboard` (web UI). + +```bash +# Install globally +npm install -g @techdebtgpt/pr-agent + +# The MCP server binary is available as pr-agent-mcp +``` + +**For local development** (working on this repository), see [MCP-LOCAL-SETUP.md](MCP-LOCAL-SETUP.md) for team setup instructions. + +See [MCP Server](#mcp-server) section for configuration details. + ## CLI Usage ### Quick Start @@ -173,6 +198,7 @@ pr-agent analyze --complexity pr-agent analyze --provider anthropic pr-agent analyze --provider openai pr-agent analyze --provider google +pr-agent analyze --provider zhipu # Use specific model pr-agent analyze --provider anthropic --model claude-sonnet-4-5-20250929 @@ -191,8 +217,26 @@ pr-agent analyze --max-cost 10.0 # Force agent mode for large diffs pr-agent analyze --agent +# Show project classification (business logic vs QA) +pr-agent analyze --show-classification + # Specify PR title manually pr-agent analyze --title "Add new authentication system" + +# Run test coverage analysis (requires coverage reports) +pr-agent analyze --scan-coverage + +# Display coverage metrics if available +pr-agent analyze --show-coverage + +# Run ESLint static analysis +pr-agent analyze --show-static-analysis + +# Enable Jira peer review integration +pr-agent analyze --peer-review + +# Full analysis with all static analysis features +pr-agent analyze --full --show-coverage --show-static-analysis ``` ### Configuration @@ -241,7 +285,8 @@ pr-agent config --reset "apiKeys": { "anthropic": "sk-ant-...", "openai": "", - "google": "" + "google": "", + "zhipu": "" }, "analysis": { "defaultMode": "full", @@ -265,6 +310,14 @@ pr-agent config --reset "verbose": false, "showStrategy": true, "showRecommendations": true + }, + "peerReview": { + "enabled": false, + "provider": "jira", + "instanceUrl": "https://your-company.atlassian.net", + "email": "your-email@company.com", + "apiToken": "your-jira-api-token", + "defaultProject": "PROJ" } } ``` @@ -282,6 +335,9 @@ export OPENAI_API_KEY="sk-..." # Google Gemini export GOOGLE_API_KEY="..." + +# Zhipu AI +export ZHIPU_API_KEY="..." ``` Add to your `.bashrc`, `.zshrc`, or `.env` file for persistence. @@ -315,6 +371,232 @@ pr-agent analyze --branch origin/feature-branch - **GitHub API errors**: Ensure `GITHUB_TOKEN` is valid, or rely on git fallback - **Custom default branch**: Configure it explicitly: `pr-agent config --set git.defaultBranch=origin/your-branch` + +## UI Dashboard + +The **PeeR-Agent Dashboard** provides a visual analytics interface to track your team's code review performance, calculate ROI, and monitor code quality trends over time. + +### Features +- **ROI Calculator**: Estimates money saved based on PR volume and automated review time. +- **Quality Trends**: Visualizes complexity and risk scores over time. +- **Contributors**: Tracks top PR creators and their average complexity. +- **Recent Activity**: Live feed of analyzed PRs with risk/complexity scores. + +### 1. Standalone Mode (CLI) +View analytics for your local analysis directly in your browser. This mode uses a local SQLite database (`pr-agent.db`) to persist your analysis history. + +```bash +# Launch the dashboard +npm run cli dashboard + +# Launch on a specific port (default: 3000) +npm run cli dashboard -- -p 3001 +``` + +Once running, the dashboard automatically opens in your default browser at `http://localhost:3000`. + +### 2. Server Deployment +When deployed as a GitHub App or long-running server (e.g., on a VPS or cloud instance), the dashboard acts as the application's home page. + +#### Configuration +- **Port**: Defaults to `3000`. Set via `PORT` environment variable. +- **Database**: Stores data in `pr-agent.db` in the root directory. Ensure the application has **write access** to this file/directory. + +```bash +# Start the server +npm run build +npm start +``` + +Access the dashboard at `http://YOUR_SERVER_IP:3000/`. + +**Note on Persistence**: The dashboard relies on `pr-agent.db`. If you are deploying to an ephemeral environment (like Heroku or Serverless), you will lose your history on restart unless you persist this file. + +## MCP Server + +> **Architecture**: PR Agent is primarily a **CLI tool**. The MCP server (`src/mcp/server.ts`) is a component that imports and reuses the CLI's core `PRAnalyzerAgent` to expose the same functionality via the Model Context Protocol. + +The MCP server **mirrors the CLI workflow exactly**, providing LLM-agnostic PR analysis for any MCP-compatible tool. It uses the same configuration file (`.pragent.config.json`) and supports all CLI features. + +### Supported MCP Clients + +- **Claude Code** - Anthropic's official CLI +- **VS Code + GitHub Copilot** - Using `.vscode/mcp.json` +- **Cursor** - AI-first code editor +- **Cline** - VS Code extension +- **Windsurf** - AI code editor + +### Configuration + +**For the repository (committed for team use):** + +PR Agent includes `.mcp.json` (Claude Code/Cursor) and `.vscode/mcp.json` (VS Code) that work after running `npm install --legacy-peer-deps && npm run build`. + +**For published npm package (global install):** + +Add to your tool's MCP configuration: + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "pr-agent-mcp" + } + } +} +``` + +From source (for local development): +```json +{ + "mcpServers": { + "pr-agent": { + "command": "node", + "args": ["/absolute/path/to/pr-agent/dist/mcp/server.js"] + } + } +} +``` + +> **Local Development**: For colleagues working on this repository, see [MCP-LOCAL-SETUP.md](MCP-LOCAL-SETUP.md) for detailed setup instructions and the `npm run mcp:setup` helper script. + +### Available Tools + +The MCP server provides two tools (defined in `server.json`): + +#### 1. `analyze` - PR/Branch Analysis + +Mirrors `pr-agent analyze` CLI command exactly. + +**What it does:** +- Parses git diff +- Detects security risks (hardcoded secrets, SQL injection, XSS, etc.) +- Calculates complexity scores (1-5 scale) +- Extracts Jira ticket references from PR title/branch/commits +- Includes architecture documentation context (if `.arch-docs` exists) +- Saves analysis to database + +**Parameters:** +- `branch` (optional): Base branch to compare against +- `staged` (optional): Analyze staged changes instead +- `title` (optional): PR title for ticket extraction +- `cwd` (optional): Working directory +- `peerReview` (optional): Enable Jira ticket validation +- `archDocs` (optional): Include architecture docs + +**Usage:** Ask your AI assistant: +``` +Analyze my current branch changes +Analyze staged changes +Analyze changes against origin/develop +``` + +#### 2. `dashboard` - Web Dashboard + +Starts the analysis history web dashboard on localhost. + +**Parameters:** +- `port` (optional): Port to run on (default: 3000) + +**Usage:** Ask your AI assistant: +``` +Start the PR Agent dashboard +Start the dashboard on port 3001 +``` + +### How It Works + +The MCP server does everything the CLI does **except** calling AI providers: + +1. **Parses git diff** (same as CLI) +2. **Detects risks** using pattern matching (same patterns as CLI) +3. **Calculates complexity** algorithmically (same algorithm as CLI) +4. **Loads arch-docs** if available (same as CLI) +5. **Extracts Jira tickets** from PR title/branch (same as CLI) +6. **Saves to database** for dashboard (same as CLI) +7. **Returns CLI-formatted output** for the calling LLM to enhance + +The calling tool's LLM then adds AI-powered insights to the analysis. + +### Integration with Other MCP Servers + +For full functionality, install these official MCP servers alongside PR Agent: + +#### Atlassian Rovo MCP Server (Jira Integration) - REQUIRED + +The PR Agent extracts Jira ticket IDs (e.g., `PROJ-123`), then Claude Code uses the official Atlassian Rovo MCP server to fetch ticket details and validate against requirements. + +**⚠️ Required Setup for Team Members (~ 1 hour initial setup)** + +This is a **mandatory** integration for the PR Agent to work correctly with peer review features. + +**Setup Instructions:** + +1. **The MCP configuration is already committed** in `.mcp.json` and `.vscode/mcp.json` - no setup needed! + +2. **Restart Claude Code** to load the MCP configuration + +3. **Authenticate with Atlassian** (OAuth - no API tokens needed!): + - When you first use Claude Code after setup, it will detect the Atlassian MCP server + - Claude Code will open a browser window for you to log in with your Atlassian account + - Grant permissions to access Jira and Confluence + - The authentication is saved and will persist across sessions + +4. **Verify the connection**: + - Go to https://id.atlassian.com/manage-profile/apps + - You should see "Atlassian MCP" listed under "Apps with access to your accounts" + +**How It Works:** +- Uses official Atlassian Rovo MCP Server (cloud-hosted by Atlassian) +- OAuth 2.1 authentication (secure, no API tokens to manage) +- Server endpoint: `https://mcp.atlassian.com/v1/sse` +- Respects your existing Jira/Confluence permissions +- Works with any Atlassian Cloud site (e.g., `your-company.atlassian.net`) + +**Troubleshooting:** +- **"Failed to reconnect to atlassian"**: Restart Claude Code and it will prompt for re-authentication +- **Connection issues**: Check your Atlassian Connected Apps at https://id.atlassian.com/manage-profile/apps +- **Permissions errors**: Make sure you have access to the Jira project in your Atlassian Cloud site + +**Documentation:** +- [Official Atlassian Rovo MCP Server docs](https://support.atlassian.com/atlassian-rovo-mcp-server/) +- [Atlassian Blog: Remote MCP Server](https://www.atlassian.com/blog/announcements/remote-mcp-server) + +#### GitHub MCP Server (Repository Management) +Provides GitHub API access for repository operations and PR management. + +**Installation**: Already configured in `.mcp.json` and `.vscode/mcp.json`. Claude Code will prompt to enable on first use. + +**Setup**: Requires GitHub authentication. See [GitHub MCP docs](https://github.com/modelcontextprotocol/servers/tree/main/src/github). + +**Workflow Example:** +``` +You: "Analyze my PR changes" + ↓ +PR Agent: Extracts PROJ-123 from branch, analyzes diff, detects risks + ↓ +Claude Code + Atlassian MCP: Fetches PROJ-123 details from Jira + ↓ +Result: Comprehensive review with ticket validation +``` + +### CLI Parity + +| Feature | CLI | MCP Server | +|---------|-----|------------| +| Config file | `.pragent.config.json` | `.pragent.config.json` | +| Diff parsing | Yes | Yes | +| Risk detection | Yes | Yes | +| Complexity scoring | Yes | Yes | +| Arch-docs support | Yes | Yes | +| Jira integration | Yes | Yes | +| Dashboard | Yes | Yes | +| AI analysis | Requires API key | Uses calling LLM | + +### Documentation + +For complete documentation, see [docs/MCP-SERVER.md](docs/MCP-SERVER.md). + ## Architecture Documentation Integration PR Agent can leverage your project's architecture documentation for context-aware analysis. @@ -512,12 +794,151 @@ Key insights from arch-docs integration: ### Benefits of Arch-Docs Integration -✅ **Context-Aware Analysis** - AI understands your specific architecture -✅ **Pattern Enforcement** - Detects violations of documented patterns -✅ **Security Alignment** - Checks against your security guidelines -✅ **Consistency** - Ensures PRs follow established conventions +✅ **Context-Aware Analysis** - AI understands your specific architecture +✅ **Pattern Enforcement** - Detects violations of documented patterns +✅ **Security Alignment** - Checks against your security guidelines +✅ **Consistency** - Ensures PRs follow established conventions ✅ **Better Recommendations** - Suggestions aligned with your architecture +## Peer Review Integration + +PR Agent can integrate with Jira to provide intelligent peer review analysis that validates your PR against linked tickets and acceptance criteria. + +### Overview + +When enabled, the peer review feature acts like a **senior developer reviewing your PR**: + +- **Extracts ticket references** from PR title, branch name, or commit messages +- **Fetches ticket details** from Jira (description, acceptance criteria, story points) +- **Rates ticket quality** to identify poorly-defined requirements +- **Validates implementation** against derived requirements +- **Provides verdict** with blockers, warnings, and recommendations + +### Setup + +1. **Configure Jira credentials** in `.pragent.config.json`: + +```json +{ + "peerReview": { + "enabled": true, + "provider": "jira", + "instanceUrl": "https://your-company.atlassian.net", + "email": "your-email@company.com", + "apiToken": "your-jira-api-token", + "defaultProject": "PROJ", + "analyzeAcceptanceCriteria": true, + "rateTicketQuality": true, + "checkScopeCreep": true + } +} +``` + +2. **Get a Jira API Token**: + - Go to [Atlassian Account Settings](https://id.atlassian.com/manage-profile/security/api-tokens) + - Click "Create API token" + - Copy the token to your config + +3. **Reference tickets in your PR**: + - PR title: `feat(PROJ-123): Add new feature` + - Branch name: `feature/PROJ-123-add-feature` + - Commit message: `PROJ-123: implement feature` + +### Usage + +```bash +# Run analysis with peer review +pr-agent analyze + +# The peer review runs automatically if enabled in config +# Or enable it for a single run: +pr-agent analyze --peer-review +``` + +### Example Output + +``` +═══════════════════════════════════════════════════════════════ + 🔍 PEER REVIEW ANALYSIS +═══════════════════════════════════════════════════════════════ + +📋 LINKED TICKET +─────────────────────────────────────────────────────────────── + Key: PROJ-123 + Title: Add user authentication + Type: STORY + Status: In Progress + Points: 5 + +📊 TICKET QUALITY RATING +─────────────────────────────────────────────────────────────── + Overall Score: 🟢 85/100 (GOOD) + + Dimension Scores: + • Description Clarity: 🟢 ████████░░ 85 + • Acceptance Criteria: 🟢 █████████░ 90 + • Testability: 🟡 ███████░░░ 75 + • Scope Definition: 🟢 ████████░░ 80 + +✅ REQUIREMENTS VALIDATION +─────────────────────────────────────────────────────────────── + Compliance: 🟢 92% + + 📊 REQUIREMENT STATUS: + ✅ Implement login endpoint with JWT tokens + ✅ Add password validation (min 8 chars) + 🟡 Create logout endpoint + └─ Endpoint exists but doesn't invalidate tokens + ✅ Store hashed passwords in database + + ❌ COVERAGE GAPS: + 🟡 [MINOR] Token invalidation not implemented + └─ Impact: Users cannot fully logout, tokens remain valid + +🎯 PEER REVIEW VERDICT +─────────────────────────────────────────────────────────────── + ✅ APPROVED (Confidence: 85%) + + The PR implements the core authentication functionality as specified. + Minor gaps in token invalidation should be addressed in a follow-up. + + Scores: + • Implementation Completeness: 🟢 ████████░░ 88 + • Quality Score: 🟢 ████████░░ 82 + + 💡 RECOMMENDATIONS: + • Add token invalidation on logout + • Consider adding rate limiting + • Add integration tests for auth flow + +═══════════════════════════════════════════════════════════════ +``` + +### Configuration Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `enabled` | boolean | `false` | Enable peer review integration | +| `provider` | string | `"jira"` | Issue tracker provider (currently only Jira) | +| `instanceUrl` | string | - | Your Jira instance URL | +| `email` | string | - | Your Jira account email | +| `apiToken` | string | - | Jira API token | +| `defaultProject` | string | - | Default project key for ticket extraction | +| `analyzeAcceptanceCriteria` | boolean | `true` | Validate against acceptance criteria | +| `rateTicketQuality` | boolean | `true` | Rate ticket definition quality | +| `generateTestSuggestions` | boolean | `true` | Generate test suggestions | +| `checkScopeCreep` | boolean | `true` | Detect scope creep in PRs | +| `includeTicketDetails` | boolean | `true` | Show ticket details in output | +| `verbose` | boolean | `false` | Enable verbose output | + +### Benefits + +✅ **Requirement Validation** - Ensures PRs implement what the ticket specifies +✅ **Quality Gate** - Catches incomplete implementations before review +✅ **Ticket Quality Feedback** - Identifies poorly-defined requirements +✅ **Scope Creep Detection** - Flags changes outside ticket scope +✅ **Senior Developer Perspective** - Catches edge cases and missing behaviors + ## GitHub Action Usage ### Setup Instructions @@ -766,7 +1187,11 @@ pr-agent/ │ │ ├── anthropic.provider.ts │ │ ├── openai.provider.ts │ │ ├── google.provider.ts +│ │ ├── zhipu.provider.ts │ │ └── factory.ts +│ ├── issue-tracker/ # Issue tracker integrations +│ │ ├── jira-mcp-client.ts # Jira API client +│ │ └── peer-review-integration.ts │ ├── tools/ # Agent tools │ │ ├── pr-analysis-tools.ts │ │ └── index.ts @@ -957,6 +1382,13 @@ Best for: Quick analysis and cost-conscious usage Best for: Alternative to Claude/GPT with competitive performance +### Zhipu AI + +- **claude-sonnet-4-20250514** - Via Anthropic-compatible API +- **glm-4** - Zhipu's native model + +Best for: Users in China or those preferring Zhipu's platform with Claude-compatible models + ## Common Use Cases ### 1. Pre-Commit Review diff --git a/REFACTORING-PLAN.md b/REFACTORING-PLAN.md new file mode 100644 index 0000000..18d931a --- /dev/null +++ b/REFACTORING-PLAN.md @@ -0,0 +1,210 @@ +# LLM-Agnostic Peer Review Refactoring Plan + +## Goal +Make peer review work without API keys in MCP mode while preserving 100% CLI functionality. + +## Current Architecture + +``` +CLI Flow: +User → analyze.command.ts → PeerReviewIntegration(llm) → JiraSubAgent(llm) + ├── rateTicketQuality() → llm.invoke() + ├── validateAcceptanceCriteria() → llm.invoke() + └── generatePeerReview() → llm.invoke() +``` + +## New Architecture + +### Core Principle +Separate **prompt building** (data + instructions) from **prompt execution** (LLM invocation). + +### Mode-Based Operation + +**Mode 1: EXECUTE (CLI)** +- Input: LLM instance with API key +- Process: Build prompts AND execute them +- Output: Analyzed results (scores, verdicts, etc.) + +**Mode 2: PROMPT_ONLY (MCP)** +- Input: No LLM needed +- Process: Build prompts but DON'T execute +- Output: Structured prompts for calling LLM to execute + +### Implementation Strategy + +#### 1. Create Execution Mode Enum +```typescript +export enum PeerReviewMode { + EXECUTE = 'execute', // CLI: Execute prompts with API key + PROMPT_ONLY = 'prompt_only' // MCP: Return prompts for calling LLM +} +``` + +#### 2. Create Prompt Structures +```typescript +export interface AnalysisPrompt { + step: 'ticketQuality' | 'acValidation' | 'peerReview'; + prompt: string; // The filled-in prompt template + schema: ZodSchema; // The expected output schema + formatInstructions: string; +} + +export interface PromptOnlyResult { + mode: 'prompt_only'; + context: JiraSubAgentContext; // All input data + prompts: AnalysisPrompt[]; // Prompts for calling LLM + instructions: string; // How to execute +} +``` + +#### 3. Refactor JiraSubAgent + +**Before:** +```typescript +class JiraSubAgent { + constructor(llm: BaseLanguageModel) {} + + async rateTicketQuality(ticket): Promise { + const chain = prompt.pipe(this.llm); + const response = await chain.invoke({...}); + return parser.parse(response); + } +} +``` + +**After:** +```typescript +class JiraSubAgent { + constructor( + private mode: PeerReviewMode, + private llm?: BaseLanguageModel // Optional now! + ) { + if (mode === PeerReviewMode.EXECUTE && !llm) { + throw new Error('LLM required in EXECUTE mode'); + } + } + + async analyze(context): Promise { + if (this.mode === PeerReviewMode.PROMPT_ONLY) { + return this.buildPrompts(context); + } else { + return this.executeAnalysis(context); + } + } + + private buildPrompts(context): PromptOnlyResult { + // Build all 3 prompts without executing + return { + mode: 'prompt_only', + context, + prompts: [ + this.buildTicketQualityPrompt(context.ticket), + this.buildACValidationPrompt(context), + this.buildPeerReviewPrompt(context) + ], + instructions: 'Execute these prompts sequentially...' + }; + } + + private async executeAnalysis(context): Promise { + // Original logic - execute all prompts with this.llm + const ticketQuality = await this.rateTicketQuality(context.ticket); + // ... rest of existing code + } +} +``` + +#### 4. Update PeerReviewIntegration + +```typescript +class PeerReviewIntegration { + constructor( + config: IssueTrackerConfig, + private mode: PeerReviewMode, + llm?: BaseLanguageModel + ) { + this.subAgent = new JiraSubAgent(mode, llm); + } + + async analyze(context): Promise { + const result = await this.subAgent.analyze(context); + + if (result.mode === 'prompt_only') { + // MCP mode: return prompts + return { + enabled: true, + mode: 'prompt_only', + prompts: result.prompts, + data: result.context + }; + } else { + // CLI mode: return analyzed results + return { + enabled: true, + mode: 'execute', + analysis: result + }; + } + } +} +``` + +#### 5. Update Callers + +**CLI (analyze.command.ts):** +```typescript +// No changes needed! Still passes LLM +const integration = createPeerReviewIntegration(config, llm); +const result = await integration.analyze(context); +// result.analysis has the scores/verdicts as before +``` + +**MCP Server:** +```typescript +// Pass PROMPT_ONLY mode, no LLM +const integration = createPeerReviewIntegration( + config, + PeerReviewMode.PROMPT_ONLY +); +const result = await integration.analyze(context); + +// Return structured prompts to calling LLM +return { + content: [{ + type: 'text', + text: formatPromptsForLLM(result.prompts, result.data) + }] +}; +``` + +## Migration Steps + +1. ✅ Create new branch: `feat/llm-agnostic-peer-review` +2. Define types: `PeerReviewMode`, `AnalysisPrompt`, `PromptOnlyResult` +3. Refactor `JiraSubAgent`: + - Add mode parameter + - Split analyze() into buildPrompts() and executeAnalysis() + - Extract prompt building logic +4. Update `PeerReviewIntegration` to support both modes +5. Update helper function `createPeerReviewIntegration()` +6. Test CLI workflow (should be unchanged) +7. Update MCP server to use PROMPT_ONLY mode +8. Test MCP server returns correct prompts + +## Testing Checklist + +**CLI (EXECUTE mode):** +- [ ] Ticket quality rating works +- [ ] AC validation works +- [ ] Peer review verdict works +- [ ] Database saves correctly +- [ ] Output format unchanged + +**MCP (PROMPT_ONLY mode):** +- [ ] Returns structured prompts +- [ ] Includes all context data +- [ ] No LLM calls attempted +- [ ] Works without API keys + +## Rollback Plan +If issues arise, revert the branch. CLI code remains unchanged on main. diff --git a/check-db.js b/check-db.js new file mode 100644 index 0000000..8b44da7 --- /dev/null +++ b/check-db.js @@ -0,0 +1,28 @@ +import Database from 'better-sqlite3'; + +const db = new Database('pr-agent.db'); + +console.log('=== Database Analysis ===\n'); + +// Check total records +const total = db.prepare('SELECT COUNT(*) as count FROM pr_analysis').get(); +console.log(`Total records: ${total.count}\n`); + +// Check latest 3 records +const latest = db.prepare('SELECT id, title, complexity, risks_count, peer_review_enabled, ticket_key, ac_compliance_percentage, timestamp FROM pr_analysis ORDER BY id DESC LIMIT 3').all(); +console.log('Latest 3 records:'); +console.table(latest); + +// Check peer review stats +const peerReviewStats = db.prepare(` + SELECT + COUNT(*) as total_analyses, + SUM(CASE WHEN peer_review_enabled = 1 THEN 1 ELSE 0 END) as with_peer_review, + AVG(ac_compliance_percentage) as avg_ac_compliance, + AVG(ticket_quality_score) as avg_ticket_quality + FROM pr_analysis +`).get(); +console.log('\n=== Peer Review Stats ==='); +console.table(peerReviewStats); + +db.close(); diff --git a/dist/action.js b/dist/action.js index 033e531..dca5a40 100644 --- a/dist/action.js +++ b/dist/action.js @@ -1,6 +1,7 @@ import * as core from '@actions/core'; import * as github from '@actions/github'; import { PRAnalyzerAgent } from './agents/pr-analyzer-agent.js'; +import { ExecutionMode } from './types/agent.types.js'; async function run() { try { // Get provider configuration from environment @@ -38,13 +39,19 @@ async function run() { // Use LangChain PRAnalyzerAgent core.info('Running LangChain agent analysis...'); const agent = new PRAnalyzerAgent({ + mode: ExecutionMode.EXECUTE, // GitHub Action always executes with API key provider, apiKey, model, }); // Analyze with the LangChain agent core.info('Parsing diff and analyzing...'); - const result = await agent.analyze(diff, pr.title); + const analysisResult = await agent.analyze(diff, pr.title); + // Type guard: GitHub Action always uses EXECUTE mode + if (analysisResult.mode === 'prompt_only') { + throw new Error('Unexpected prompt-only result in GitHub Action EXECUTE mode'); + } + const result = analysisResult; core.info(`Analysis complete: ${result.fileAnalyses.size} files analyzed`); // Format for quick reading (1 minute scan) let summary = ''; diff --git a/dist/action.js.map b/dist/action.js.map index 0155a43..64a2259 100644 --- a/dist/action.js.map +++ b/dist/action.js.map @@ -1 +1 @@ -{"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAoB,MAAM,wBAAwB,CAAC;AAEzE,KAAK,UAAU,GAAG;IAChB,IAAI,CAAC;QACH,8CAA8C;QAC9C,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,WAAW,CAAC,CAAC,WAAW,EAAuC,CAAC;QAC7G,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACzG,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;QAEzC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,SAAS,CAAC,wFAAwF,CAAC,CAAC;YACzG,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,SAAS,CAAC,+CAA+C,CAAC,CAAC;YAChE,OAAO;QACT,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,sBAAsB,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAEnF,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QAC3B,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;QAEzD,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,IAAI,CAAC,SAAS,CAAC,oDAAoD,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC,MAAM,OAAO,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;QAEpE,eAAe;QACf,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAEhD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,MAAM,aAAa,CAAC,CAAC;QAElD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,sCAAsC,CAAC,CAAC;YACvD,OAAO;QACT,CAAC;QAED,gCAAgC;QAChC,IAAI,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC;YAChC,IAAI,EAAE,aAAa,CAAC,OAAO,EAAG,6CAA6C;YAC3E,QAAQ;YACR,MAAM;YACN,KAAK;SACN,CAAC,CAAC;QAEH,mCAAmC;QACnC,IAAI,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC3C,MAAM,cAAc,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QAE3D,qDAAqD;QACrD,IAAI,cAAc,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,MAAM,GAAG,cAA6B,CAAC;QAE7C,IAAI,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,YAAY,CAAC,IAAI,iBAAiB,CAAC,CAAC;QAE3E,2CAA2C;QAC3C,IAAI,OAAO,GAAG,EAAE,CAAC;QAEjB,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC;QACxF,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;QACtF,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC;QAE7C,kBAAkB;QAClB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,IAAI,mBAAmB,MAAM,CAAC,OAAO,MAAM,CAAC;QACrD,CAAC;QAED,MAAM,UAAU,GAA0E,EAAE,CAAC;QAE7F,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAG,CAAC,GAAG,aAAa,EAAE,GAAG,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACjE,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAQ,EAAE,EAAE;gBAC5B,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI,EAAE,KAAK;oBACX,OAAO,EAAE,GAAG;oBACZ,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,IAAI;iBAC3B,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAED,gCAAgC;QAChC,IAAI,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChE,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAW,EAAE,EAAE;gBACzD,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI,EAAE,gBAAgB;oBACtB,OAAO,EAAE,GAAG;oBACZ,MAAM,EAAE,IAAI;iBACb,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,0BAA0B,CAAC;YAEtC,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;gBAC5B,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;oBAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC;oBAC3B,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC/D,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;oBAC3E,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC;oBACzE,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;oBAElE,yEAAyE;oBACzE,OAAO,IAAI,KAAK,WAAW,KAAK,YAAY,MAAM,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,QAAQ,aAAa,GAAG,WAAW,IAAI,CAAC;oBAC9G,wBAAwB;oBACxB,OAAO,IAAI,QAAQ,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;gBAChF,CAAC;qBAAM,CAAC;oBACN,iDAAiD;oBACjD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC;oBAC3B,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC;oBAEzE,2CAA2C;oBAC3C,IAAI,YAAY,GAAG,IAAI,CAAC;oBACxB,IAAI,aAAa,GAAG,SAAS,CAAC;oBAC9B,IAAI,OAAO,GAAG,GAAG,CAAC;oBAElB,gEAAgE;oBAChE,IAAI,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE,CAAC;wBACjC,YAAY,GAAG,IAAI,CAAC;wBACpB,aAAa,GAAG,UAAU,CAAC;wBAC3B,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;oBACvE,CAAC;yBAAM,IAAI,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC;wBACvC,YAAY,GAAG,IAAI,CAAC;wBACpB,aAAa,GAAG,SAAS,CAAC;wBAC1B,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;oBACtE,CAAC;yBAAM,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;wBAClD,YAAY,GAAG,IAAI,CAAC;wBACpB,aAAa,GAAG,UAAU,CAAC;oBAC7B,CAAC;oBAED,6DAA6D;oBAC7D,OAAO,IAAI,KAAK,WAAW,KAAK,YAAY,MAAM,aAAa,GAAG,WAAW,IAAI,CAAC;oBAClF,6CAA6C;oBAC7C,OAAO,IAAI,QAAQ,YAAY,MAAM,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;gBACvK,CAAC;gBACD,WAAW,EAAE,CAAC;YAChB,CAAC,CAAC,CAAC;YAEH,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;gBACnB,OAAO,IAAI,IAAI,UAAU,GAAG,CAAC,0BAA0B,CAAC;YAC1D,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,+CAA+C,CAAC;QAC7D,CAAC;QAED,yBAAyB;QACzB,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;YAC3B,OAAO,IAAI,8BAA8B,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,GAAG,CAAC;QACtF,CAAC;QAED,eAAe;QACf,MAAM,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAE3D,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAElC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,SAAS,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAY,EAAE,OAAe;IACrD,IAAI,CAAC;QACH,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;QAEzD,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAE3C,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;YACzD,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK;YAC7B,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,WAAW,EAAE,EAAE,CAAC,MAAM;SACvB,CAAC,CAAC;QAEH,mDAAmD;QACnD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE;YAC1B,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC;gBAC/C,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAE5B,OAAO,gBAAgB,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,QAAQ;EACrD,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ;MACpF,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ;EAC5D,KAAK,EAAE,CAAC;QACN,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,QAAgB,EAAE,OAAe,EAAE,UAAe,EAAE,OAAe;IAC5F,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAE3C,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;YACtC,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK;YAC7B,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,YAAY,EAAE,QAAQ;YACtB,IAAI,EAAE,kDAAkD,OAAO,EAAE;SAClE,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,GAAG,EAAE,CAAC"} \ No newline at end of file diff --git a/dist/actions/code-suggestion/codesugestions.d.ts b/dist/actions/code-suggestion/codesugestions.d.ts deleted file mode 100644 index 7b209fb..0000000 --- a/dist/actions/code-suggestion/codesugestions.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -export declare function buildClaudeCodeSuggestionPrompt(params: { - prTitle?: string; - repo?: string; - branch?: string; - filePath?: string | null; - reviewerComment: string; - codeSnippet: string; -}): string; -/** - * Suggest a code fix based on a reviewer inline comment using the existing analyzer. - * Non-invasive: uses analyzeWithClaude same way src/action.ts does. - */ -export declare function suggestFixFromComment(params: { - pr: any; - reviewerComment: string; - filePath: string; - codeSnippet: string; - apiKey?: string; -}): Promise; -/** - * Minimal helper to prepare a file replacement object. - * Returns null when suggestion is "NO CHANGE" or empty. - * Keeps behavior conservative (full file replacement) so it won't modify existing flows unexpectedly. - */ -export declare function prepareFileReplacement(filePath: string, originalContent: string, suggestion: string): { - path: string; - newContent: string; -} | null; diff --git a/dist/actions/code-suggestion/codesugestions.js b/dist/actions/code-suggestion/codesugestions.js deleted file mode 100644 index 7834594..0000000 --- a/dist/actions/code-suggestion/codesugestions.js +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.buildClaudeCodeSuggestionPrompt = buildClaudeCodeSuggestionPrompt; -exports.suggestFixFromComment = suggestFixFromComment; -exports.prepareFileReplacement = prepareFileReplacement; -const analyzer_1 = require("../../analyzer"); -function buildClaudeCodeSuggestionPrompt(params) { - const { prTitle, repo, branch, filePath, reviewerComment, codeSnippet } = params; - return ` -You are an expert software engineer and code-fixer. You will take a reviewer comment and the associated code snippet and produce the corrected code snippet only. - -Context: -- Repo: ${repo ?? "(unknown)"} -- Branch: ${branch ?? "(unknown)"} -- PR Title: ${prTitle ?? "(unknown)"} -- File: ${filePath ?? "(unknown)"} - -Reviewer comment: -${reviewerComment.trim()} - -Original code snippet: -\`\`\` -${codeSnippet} -\`\`\` - -Task: -1) Apply the reviewer’s requested changes to the provided code snippet. -2) Output rules (MUST follow exactly): - - Return only the corrected code snippet (no explanations, no markdown fences, no extra text). - - If only a few lines changed you may return only the updated lines, but prefer returning the full corrected snippet when structural/context changes are required. - - Preserve original code style and indentation. - - If no changes are needed, reply with exactly: NO CHANGE - - Do not include filenames, metadata, or commentary. - -Produce the corrected code now. -`.trim(); -} -/** - * Suggest a code fix based on a reviewer inline comment using the existing analyzer. - * Non-invasive: uses analyzeWithClaude same way src/action.ts does. - */ -async function suggestFixFromComment(params) { - const { pr, reviewerComment, filePath, codeSnippet } = params; - const apiKey = params.apiKey ?? process.env.ANTHROPIC_API_KEY; - if (!apiKey) { - throw new Error('ANTHROPIC_API_KEY environment variable is required for code suggestions'); - } - const prompt = buildClaudeCodeSuggestionPrompt({ - prTitle: pr?.title, - repo: pr?.repo ?? undefined, - branch: pr?.branch ?? undefined, - filePath, - reviewerComment, - codeSnippet, - }); - // analyzeWithClaude in this repo is used as analyzeWithClaude(text, title, apiKey) - const title = pr?.title ?? undefined; - const result = await (0, analyzer_1.analyzeWithClaude)(prompt, title, apiKey); - return (typeof result === 'string' ? result : String(result)).trim(); -} -/** - * Minimal helper to prepare a file replacement object. - * Returns null when suggestion is "NO CHANGE" or empty. - * Keeps behavior conservative (full file replacement) so it won't modify existing flows unexpectedly. - */ -function prepareFileReplacement(filePath, originalContent, suggestion) { - const trimmed = suggestion?.trim?.(); - if (!trimmed || trimmed === 'NO CHANGE') - return null; - // Default to full replacement to avoid risky partial patching automatically. - return { - path: filePath, - newContent: trimmed - }; -} -//# sourceMappingURL=codesugestions.js.map \ No newline at end of file diff --git a/dist/actions/code-suggestion/codesugestions.js.map b/dist/actions/code-suggestion/codesugestions.js.map deleted file mode 100644 index af8c48b..0000000 --- a/dist/actions/code-suggestion/codesugestions.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"codesugestions.js","sourceRoot":"","sources":["../../../src/actions/code-suggestion/codesugestions.ts"],"names":[],"mappings":";;AAEA,0EAsCC;AAMD,sDA2BC;AAOD,wDASC;AAzFD,6CAAmD;AAEnD,SAAgB,+BAA+B,CAAC,MAO/C;IACG,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IAEjF,OAAO;;;;UAID,IAAI,IAAI,WAAW;YACjB,MAAM,IAAI,WAAW;cACnB,OAAO,IAAI,WAAW;UAC1B,QAAQ,IAAI,WAAW;;;EAG/B,eAAe,CAAC,IAAI,EAAE;;;;EAItB,WAAW;;;;;;;;;;;;;CAaZ,CAAC,IAAI,EAAE,CAAC;AACT,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,qBAAqB,CAAC,MAM3C;IACG,MAAM,EAAE,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAE9D,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,MAAM,GAAG,+BAA+B,CAAC;QAC3C,OAAO,EAAE,EAAE,EAAE,KAAK;QAClB,IAAI,EAAG,EAAU,EAAE,IAAI,IAAI,SAAS;QACpC,MAAM,EAAG,EAAU,EAAE,MAAM,IAAI,SAAS;QACxC,QAAQ;QACR,eAAe;QACf,WAAW;KACd,CAAC,CAAC;IAEH,mFAAmF;IACnF,MAAM,KAAK,GAAG,EAAE,EAAE,KAAK,IAAI,SAAS,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,IAAA,4BAAiB,EAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC9D,OAAO,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACzE,CAAC;AAED;;;;GAIG;AACH,SAAgB,sBAAsB,CAAC,QAAgB,EAAE,eAAuB,EAAE,UAAkB;IAChG,MAAM,OAAO,GAAG,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC;IACrC,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAErD,6EAA6E;IAC7E,OAAO;QACH,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,OAAO;KACtB,CAAC;AACN,CAAC"} \ No newline at end of file diff --git a/dist/agent-analyzer.d.ts b/dist/agent-analyzer.d.ts deleted file mode 100644 index 94e4a91..0000000 --- a/dist/agent-analyzer.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AIProviderConfig, AnalysisResponse } from './providers/types'; -/** - * Agent-based analysis for large PRs - * Splits the PR into chunks and analyzes them separately, then aggregates results - */ -export declare function analyzeLargePR(diff: string, title: string | undefined, config: AIProviderConfig, repository?: string, prNumber?: number): Promise; diff --git a/dist/agent-analyzer.js b/dist/agent-analyzer.js deleted file mode 100644 index b516abc..0000000 --- a/dist/agent-analyzer.js +++ /dev/null @@ -1,165 +0,0 @@ -"use strict"; -// Agent-based Analyzer for Large PRs -// Handles PRs that exceed normal token limits by using chunking and multi-pass analysis -Object.defineProperty(exports, "__esModule", { value: true }); -exports.analyzeLargePR = analyzeLargePR; -const factory_1 = require("./providers/factory"); -const constants_1 = require("./providers/constants"); -const MAX_NORMAL_TOKENS = 15000; // 15k tokens threshold -const CHUNK_OVERLAP_TOKENS = 1000; // Overlap between chunks for context -/** - * Estimate tokens from text - */ -function estimateTokens(text) { - return Math.ceil(text.length / constants_1.PROVIDER_CONSTANTS.CHARS_PER_TOKEN); -} -/** - * Split diff into chunks that fit within token limits - */ -function chunkDiff(diff, maxChunkTokens) { - const chunks = []; - const lines = diff.split('\n'); - let currentChunk = []; - let currentTokens = 0; - let startIndex = 0; - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - const lineTokens = estimateTokens(line); - if (currentTokens + lineTokens > maxChunkTokens && currentChunk.length > 0) { - // Save current chunk - const chunkContent = currentChunk.join('\n'); - chunks.push({ - content: chunkContent, - startIndex, - endIndex: startIndex + chunkContent.length, - tokens: currentTokens - }); - // Start new chunk with overlap (include last N lines for context) - const overlapLines = Math.floor(CHUNK_OVERLAP_TOKENS / (estimateTokens(line) || 1)); - currentChunk = lines.slice(Math.max(0, i - overlapLines), i + 1); - currentTokens = estimateTokens(currentChunk.join('\n')); - startIndex = chunks.length > 0 ? chunks[chunks.length - 1].endIndex - overlapLines * 50 : 0; - } - else { - currentChunk.push(line); - currentTokens += lineTokens; - } - } - // Add remaining chunk - if (currentChunk.length > 0) { - chunks.push({ - content: currentChunk.join('\n'), - startIndex, - endIndex: startIndex + currentChunk.join('\n').length, - tokens: currentTokens - }); - } - return chunks; -} -/** - * Analyze a single chunk - */ -async function analyzeChunk(chunk, chunkIndex, totalChunks, title, config) { - const provider = (0, factory_1.createProvider)(config); - const chunkPrompt = ` -You are analyzing chunk ${chunkIndex + 1} of ${totalChunks} from a large pull request. -${title ? `PR Title: ${title}` : ''} - -This is a portion of the PR diff: -${chunk.content} - -Provide a focused analysis for this chunk: -1. **Summary**: What does this specific portion change? -2. **Risks**: Any issues specific to this chunk? -3. **Complexity**: Rate complexity for this chunk (1-5). - -Keep the analysis concise and focused on this specific portion.`; - const request = { - diff: chunk.content, - title: title ? `${title} (chunk ${chunkIndex + 1}/${totalChunks})` : undefined - }; - const response = await provider.analyze(request); - return { - summary: response.summary, - risks: response.risks, - complexity: response.complexity - }; -} -/** - * Aggregate chunk analyses into a comprehensive result - */ -async function aggregateAnalyses(chunkAnalyses, config, originalTitle) { - // Aggregate risks (remove duplicates) - const allRisks = new Set(); - chunkAnalyses.forEach(chunk => { - chunk.risks.forEach(risk => allRisks.add(risk)); - }); - // Calculate average complexity - const avgComplexity = Math.round(chunkAnalyses.reduce((sum, chunk) => sum + chunk.complexity, 0) / chunkAnalyses.length); - // Combine summaries - const combinedSummary = chunkAnalyses - .map((chunk, idx) => `[Part ${idx + 1}] ${chunk.summary}`) - .join('\n\n'); - const provider = (0, factory_1.createProvider)(config); - // Use a specialized aggregation prompt - const aggregationDiff = ` -This is a synthesized analysis from ${chunkAnalyses.length} parts of a large pull request. - -${originalTitle ? `PR Title: ${originalTitle}` : ''} - -Analysis Summary: -${combinedSummary} - -Consolidated Risks Identified: -${Array.from(allRisks).map(r => `- ${r}`).join('\n') || 'None identified'} - -Please provide a cohesive, comprehensive analysis that synthesizes these parts into a unified review.`; - const request = { - diff: aggregationDiff, - title: originalTitle ? `${originalTitle} (Aggregated from ${chunkAnalyses.length} parts)` : undefined - }; - const aggregated = await provider.analyze(request); - // Merge the aggregated result with our consolidated data - return { - ...aggregated, - risks: aggregated.risks.length > 0 ? aggregated.risks : Array.from(allRisks), - complexity: aggregated.complexity || avgComplexity, - provider: config.provider, - model: config.model - }; -} -/** - * Agent-based analysis for large PRs - * Splits the PR into chunks and analyzes them separately, then aggregates results - */ -async function analyzeLargePR(diff, title, config, repository, prNumber) { - const totalTokens = estimateTokens(diff); - if (totalTokens <= MAX_NORMAL_TOKENS) { - // Fallback to normal analysis if somehow called for small PR - const provider = (0, factory_1.createProvider)(config); - return await provider.analyze({ diff, title, repository, prNumber }); - } - console.info(`📊 Large PR detected: ~${totalTokens.toLocaleString()} tokens. Using agent-based chunking analysis...`); - // Calculate chunk size (leave room for prompt and response) - const maxChunkTokens = Math.floor((config.maxTokens || 15000) * 0.8 // Use 80% of max tokens for chunk content - ); - // Split into chunks - const chunks = chunkDiff(diff, maxChunkTokens); - console.info(`📦 Split into ${chunks.length} chunks for analysis`); - // Analyze each chunk - const chunkAnalyses = await Promise.all(chunks.map((chunk, idx) => analyzeChunk(chunk, idx, chunks.length, title, config))); - console.info(`✅ Completed analysis of all ${chunks.length} chunks. Aggregating...`); - // Aggregate results - const finalAnalysis = await aggregateAnalyses(chunkAnalyses, config, title); - return { - ...finalAnalysis, - provider: config.provider, - model: config.model, - // Mark as agent-analyzed - recommendations: [ - ...(finalAnalysis.recommendations || []), - `This PR was analyzed using agent-based chunking due to size (~${totalTokens.toLocaleString()} tokens across ${chunks.length} chunks)` - ] - }; -} -//# sourceMappingURL=agent-analyzer.js.map \ No newline at end of file diff --git a/dist/agent-analyzer.js.map b/dist/agent-analyzer.js.map deleted file mode 100644 index 0a2870b..0000000 --- a/dist/agent-analyzer.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"agent-analyzer.js","sourceRoot":"","sources":["../src/agent-analyzer.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/agent/state.d.ts b/dist/agent/state.d.ts deleted file mode 100644 index 19153a8..0000000 --- a/dist/agent/state.d.ts +++ /dev/null @@ -1,121 +0,0 @@ -/** - * LangGraph Agent State for PR Analysis - * Defines the state structure that flows through the agent workflow - */ -/** - * Agent State Interface - */ -export interface PRAgentStateType { - diff: string; - title?: string; - mode: { - summary: boolean; - risks: boolean; - complexity: boolean; - }; - strategy: 'quick' | 'comprehensive' | 'deep-dive'; - reasoning: string[]; - parsedFiles: Array<{ - path: string; - status: string; - additions: number; - deletions: number; - language?: string; - }>; - fileAnalyses: Array<{ - file: string; - complexity: number; - risks: string[]; - patterns: string[]; - changes: { - additions: number; - deletions: number; - total: number; - }; - }>; - designPatterns: string[]; - architecturalChanges: string[]; - overallRisks: Array<{ - severity: string; - category: string; - description: string; - }>; - summary: string; - overallComplexity: number; - recommendations: string[]; - insights: string[]; - tokensUsed: number; - iterationCount: number; - completed: boolean; - needsRefinement: boolean; - refinementQuestions: string[]; -} -/** - * LangGraph State Annotation - * This defines how the state is updated throughout the workflow - */ -export declare const PRAgentState: import("@langchain/langgraph").AnnotationRoot<{ - diff: { - (): import("@langchain/langgraph").LastValue; - (annotation: import("@langchain/langgraph").SingleReducer): import("@langchain/langgraph").BinaryOperatorAggregate; - Root: (sd: S) => import("@langchain/langgraph").AnnotationRoot; - }; - title: { - (): import("@langchain/langgraph").LastValue; - (annotation: import("@langchain/langgraph").SingleReducer): import("@langchain/langgraph").BinaryOperatorAggregate; - Root: (sd: S) => import("@langchain/langgraph").AnnotationRoot; - }; - mode: { - (): import("@langchain/langgraph").LastValue<{ - summary: boolean; - risks: boolean; - complexity: boolean; - }>; - (annotation: import("@langchain/langgraph").SingleReducer<{ - summary: boolean; - risks: boolean; - complexity: boolean; - }, { - summary: boolean; - risks: boolean; - complexity: boolean; - }>): import("@langchain/langgraph").BinaryOperatorAggregate<{ - summary: boolean; - risks: boolean; - complexity: boolean; - }, { - summary: boolean; - risks: boolean; - complexity: boolean; - }>; - Root: (sd: S) => import("@langchain/langgraph").AnnotationRoot; - }; - strategy: { - (): import("@langchain/langgraph").LastValue<"quick" | "comprehensive" | "deep-dive">; - (annotation: import("@langchain/langgraph").SingleReducer<"quick" | "comprehensive" | "deep-dive", "quick" | "comprehensive" | "deep-dive">): import("@langchain/langgraph").BinaryOperatorAggregate<"quick" | "comprehensive" | "deep-dive", "quick" | "comprehensive" | "deep-dive">; - Root: (sd: S) => import("@langchain/langgraph").AnnotationRoot; - }; - reasoning: import("@langchain/langgraph").BinaryOperatorAggregate; - parsedFiles: import("@langchain/langgraph").BinaryOperatorAggregate; - fileAnalyses: import("@langchain/langgraph").BinaryOperatorAggregate; - designPatterns: import("@langchain/langgraph").BinaryOperatorAggregate; - architecturalChanges: import("@langchain/langgraph").BinaryOperatorAggregate; - overallRisks: import("@langchain/langgraph").BinaryOperatorAggregate; - summary: import("@langchain/langgraph").BinaryOperatorAggregate; - overallComplexity: import("@langchain/langgraph").BinaryOperatorAggregate; - recommendations: import("@langchain/langgraph").BinaryOperatorAggregate; - insights: import("@langchain/langgraph").BinaryOperatorAggregate; - tokensUsed: import("@langchain/langgraph").BinaryOperatorAggregate; - iterationCount: import("@langchain/langgraph").BinaryOperatorAggregate; - completed: import("@langchain/langgraph").BinaryOperatorAggregate; - needsRefinement: import("@langchain/langgraph").BinaryOperatorAggregate; - refinementQuestions: import("@langchain/langgraph").BinaryOperatorAggregate; -}>; -/** - * Initial state creator - */ -export declare function createInitialState(diff: string, title?: string, mode?: { - summary: boolean; - risks: boolean; - complexity: boolean; -}): Partial; diff --git a/dist/agent/state.js b/dist/agent/state.js deleted file mode 100644 index 4dfe522..0000000 --- a/dist/agent/state.js +++ /dev/null @@ -1,107 +0,0 @@ -"use strict"; -/** - * LangGraph Agent State for PR Analysis - * Defines the state structure that flows through the agent workflow - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.PRAgentState = void 0; -exports.createInitialState = createInitialState; -const langgraph_1 = require("@langchain/langgraph"); -/** - * LangGraph State Annotation - * This defines how the state is updated throughout the workflow - */ -exports.PRAgentState = langgraph_1.Annotation.Root({ - // Input fields - diff: (langgraph_1.Annotation), - title: (langgraph_1.Annotation), - mode: (langgraph_1.Annotation), - // Strategy - strategy: (langgraph_1.Annotation), - reasoning: (0, langgraph_1.Annotation)({ - reducer: (current, update) => [...current, ...update], - default: () => [], - }), - // Parsed data - parsedFiles: (0, langgraph_1.Annotation)({ - default: () => [], - }), - // File analyses - fileAnalyses: (0, langgraph_1.Annotation)({ - reducer: (current, update) => [...current, ...update], - default: () => [], - }), - // Insights - designPatterns: (0, langgraph_1.Annotation)({ - reducer: (current, update) => [...current, ...update], - default: () => [], - }), - architecturalChanges: (0, langgraph_1.Annotation)({ - reducer: (current, update) => [...current, ...update], - default: () => [], - }), - overallRisks: (0, langgraph_1.Annotation)({ - reducer: (current, update) => [...current, ...update], - default: () => [], - }), - // Results - summary: (0, langgraph_1.Annotation)({ - default: () => '', - }), - overallComplexity: (0, langgraph_1.Annotation)({ - default: () => 0, - }), - recommendations: (0, langgraph_1.Annotation)({ - default: () => [], - }), - insights: (0, langgraph_1.Annotation)({ - reducer: (current, update) => [...current, ...update], - default: () => [], - }), - // Metadata - tokensUsed: (0, langgraph_1.Annotation)({ - reducer: (current, update) => current + update, - default: () => 0, - }), - iterationCount: (0, langgraph_1.Annotation)({ - reducer: (current, update) => current + update, - default: () => 0, - }), - completed: (0, langgraph_1.Annotation)({ - default: () => false, - }), - // Refinement - needsRefinement: (0, langgraph_1.Annotation)({ - default: () => false, - }), - refinementQuestions: (0, langgraph_1.Annotation)({ - default: () => [], - }), -}); -/** - * Initial state creator - */ -function createInitialState(diff, title, mode) { - return { - diff, - title, - mode: mode || { summary: true, risks: true, complexity: true }, - strategy: 'comprehensive', - reasoning: [], - parsedFiles: [], - fileAnalyses: [], - designPatterns: [], - architecturalChanges: [], - overallRisks: [], - summary: '', - overallComplexity: 0, - recommendations: [], - insights: [], - tokensUsed: 0, - iterationCount: 0, - completed: false, - needsRefinement: false, - refinementQuestions: [], - }; -} -//# sourceMappingURL=state.js.map \ No newline at end of file diff --git a/dist/agent/state.js.map b/dist/agent/state.js.map deleted file mode 100644 index 991460c..0000000 --- a/dist/agent/state.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/agent/state.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/agent/tools.d.ts b/dist/agent/tools.d.ts deleted file mode 100644 index e0d7019..0000000 --- a/dist/agent/tools.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * LangChain Tools for PR Analysis Agent - * These tools allow the agent to perform specific analysis tasks - */ -/** - * Parse git diff into structured file changes - */ -export declare const parseDiffTool: any; -/** - * Analyze a specific file for complexity and patterns - */ -export declare const analyzeFileTool: any; -/** - * Detect design patterns and architectural decisions - */ -export declare const detectPatternsTool: any; -/** - * Assess risks and security concerns - */ -export declare const assessRisksTool: any; -/** - * Generate recommendations based on analysis - */ -export declare const generateRecommendationsTool: any; -/** - * Export all tools as an array - */ -export declare const prAnalysisTools: any[]; diff --git a/dist/agent/tools.js b/dist/agent/tools.js deleted file mode 100644 index 00045bd..0000000 --- a/dist/agent/tools.js +++ /dev/null @@ -1,365 +0,0 @@ -"use strict"; -/** - * LangChain Tools for PR Analysis Agent - * These tools allow the agent to perform specific analysis tasks - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.prAnalysisTools = exports.generateRecommendationsTool = exports.assessRisksTool = exports.detectPatternsTool = exports.analyzeFileTool = exports.parseDiffTool = void 0; -const tools_1 = require("@langchain/core/tools"); -const zod_1 = require("zod"); -/** - * Parse git diff into structured file changes - */ -exports.parseDiffTool = new tools_1.DynamicStructuredTool({ - name: 'parse_diff', - description: `Parse a git diff string into structured file changes. - Returns list of files with their paths, change types, additions, deletions, and diff content. - Use this first to understand what files were changed.`, - schema: zod_1.z.object({ - diff: zod_1.z.string().describe('The git diff string to parse'), - }), - func: async ({ diff }) => { - const files = []; - const diffBlocks = diff.split(/^diff --git /m).filter(Boolean); - for (const block of diffBlocks) { - const lines = block.split('\n'); - const firstLine = lines[0]; - // Extract file paths - const match = firstLine.match(/a\/(.+?) b\/(.+?)$/); - if (!match) - continue; - const oldPath = match[1]; - const newPath = match[2]; - const path = newPath !== '/dev/null' ? newPath : oldPath; - // Determine status - let status = 'M'; // Modified - if (oldPath === '/dev/null') - status = 'A'; // Added - if (newPath === '/dev/null') - status = 'D'; // Deleted - // Count additions and deletions - let additions = 0; - let deletions = 0; - for (const line of lines) { - if (line.startsWith('+') && !line.startsWith('+++')) - additions++; - if (line.startsWith('-') && !line.startsWith('---')) - deletions++; - } - // Detect language from file extension - const language = detectLanguage(path); - files.push({ - path, - status, - additions, - deletions, - diff: block, - language, - }); - } - return JSON.stringify({ - totalFiles: files.length, - files: files.map((f) => ({ - path: f.path, - status: f.status, - additions: f.additions, - deletions: f.deletions, - language: f.language, - })), - summary: `Found ${files.length} changed files: ${files.filter((f) => f.status === 'A').length} added, ${files.filter((f) => f.status === 'M').length} modified, ${files.filter((f) => f.status === 'D').length} deleted`, - }); - }, -}); -/** - * Analyze a specific file for complexity and patterns - */ -exports.analyzeFileTool = new tools_1.DynamicStructuredTool({ - name: 'analyze_file', - description: `Analyze a specific file's changes for complexity, patterns, and potential issues. - Use this to deep-dive into specific files that seem important or risky.`, - schema: zod_1.z.object({ - filePath: zod_1.z.string().describe('Path of the file to analyze'), - diff: zod_1.z.string().describe('The diff content for this file'), - context: zod_1.z.string().optional().describe('Additional context about this file'), - }), - func: async ({ filePath, diff, context }) => { - const lines = diff.split('\n'); - const addedLines = lines.filter((l) => l.startsWith('+') && !l.startsWith('+++')).length; - const deletedLines = lines.filter((l) => l.startsWith('-') && !l.startsWith('---')).length; - const totalChanges = addedLines + deletedLines; - // Calculate complexity score (1-5) - let complexity = 1; - if (totalChanges > 200) - complexity = 5; - else if (totalChanges > 100) - complexity = 4; - else if (totalChanges > 50) - complexity = 3; - else if (totalChanges > 20) - complexity = 2; - // Detect patterns and potential issues - const patterns = []; - const risks = []; - // Pattern detection - if (diff.includes('class ') || diff.includes('interface ')) - patterns.push('OOP structures'); - if (diff.includes('async ') || diff.includes('await ')) - patterns.push('Async operations'); - if (diff.includes('import ') || diff.includes('require(')) - patterns.push('Dependencies'); - if (diff.includes('export ')) - patterns.push('Exported functionality'); - if (diff.includes('TODO') || diff.includes('FIXME')) - patterns.push('TODO/FIXME comments'); - // Risk detection - if (diff.includes('eval(') || diff.includes('dangerouslySetInnerHTML')) { - risks.push('Potential security vulnerability: unsafe code execution'); - } - if (diff.includes('password') || diff.includes('secret') || diff.includes('api_key')) { - risks.push('Potential sensitive data exposure'); - } - if (diff.includes('DELETE FROM') || diff.includes('DROP TABLE')) { - risks.push('Database destructive operations'); - } - if (totalChanges > 150) { - risks.push('Large change - may need careful review'); - } - if (diff.includes('// @ts-ignore') || diff.includes('// eslint-disable')) { - risks.push('Linting/type checking disabled'); - } - return JSON.stringify({ - file: filePath, - complexity, - changes: { - additions: addedLines, - deletions: deletedLines, - total: totalChanges, - }, - patterns, - risks, - language: detectLanguage(filePath), - }); - }, -}); -/** - * Detect design patterns and architectural decisions - */ -exports.detectPatternsTool = new tools_1.DynamicStructuredTool({ - name: 'detect_patterns', - description: `Detect design patterns, architectural decisions, and code structures across all changes. - Use this to understand the broader impact and design approach of the PR.`, - schema: zod_1.z.object({ - diff: zod_1.z.string().describe('The complete diff to analyze'), - fileList: zod_1.z.array(zod_1.z.string()).describe('List of changed file paths'), - }), - func: async ({ diff, fileList }) => { - const patterns = []; - const architecturalChanges = []; - // Detect testing patterns - const testFiles = fileList.filter((f) => f.includes('.test.') || f.includes('.spec.') || f.includes('__tests__')); - if (testFiles.length > 0) { - patterns.push(`Testing: ${testFiles.length} test files modified`); - } - // Detect configuration changes - const configFiles = fileList.filter((f) => f.includes('config') || f.includes('.json') || f.includes('.yml') || f.includes('.yaml')); - if (configFiles.length > 0) { - architecturalChanges.push(`Configuration: ${configFiles.length} config files changed`); - } - // Detect API changes - if (diff.includes('app.get(') || diff.includes('app.post(') || diff.includes('@route')) { - patterns.push('API routes modified'); - } - // Detect database changes - if (diff.includes('CREATE TABLE') || diff.includes('ALTER TABLE') || diff.includes('migration')) { - architecturalChanges.push('Database schema changes'); - } - // Detect dependency changes - if (fileList.some((f) => f.includes('package.json') || f.includes('requirements.txt'))) { - architecturalChanges.push('Dependencies updated'); - } - // Detect UI changes - const uiFiles = fileList.filter((f) => f.includes('.tsx') || f.includes('.jsx') || f.includes('.vue') || f.includes('.css')); - if (uiFiles.length > 0) { - patterns.push(`UI: ${uiFiles.length} UI files modified`); - } - // Detect build/CI changes - if (fileList.some((f) => f.includes('Dockerfile') || f.includes('.github') || f.includes('ci.'))) { - architecturalChanges.push('Build/CI configuration changed'); - } - return JSON.stringify({ - designPatterns: patterns, - architecturalChanges, - scope: { - files: fileList.length, - testFiles: testFiles.length, - configFiles: configFiles.length, - uiFiles: uiFiles.length, - }, - }); - }, -}); -/** - * Assess risks and security concerns - */ -exports.assessRisksTool = new tools_1.DynamicStructuredTool({ - name: 'assess_risks', - description: `Assess overall risks, security concerns, and breaking changes in the PR. - Use this to identify critical issues that need attention.`, - schema: zod_1.z.object({ - diff: zod_1.z.string().describe('The complete diff to analyze'), - fileAnalyses: zod_1.z.array(zod_1.z.any()).describe('Array of file analysis results'), - }), - func: async ({ diff, fileAnalyses }) => { - const risks = []; - // Aggregate file-level risks - for (const analysis of fileAnalyses) { - if (analysis.risks && analysis.risks.length > 0) { - for (const risk of analysis.risks) { - risks.push({ - severity: 'medium', - category: 'file-level', - description: `${analysis.file}: ${risk}`, - }); - } - } - } - // Check for high-impact changes - const criticalPatterns = [ - { pattern: /process\.env\[['"].*SECRET/g, severity: 'high', desc: 'Environment variable secret handling' }, - { pattern: /eval\(/g, severity: 'critical', desc: 'Code evaluation (eval) detected' }, - { pattern: /dangerouslySetInnerHTML/g, severity: 'high', desc: 'XSS risk: dangerouslySetInnerHTML' }, - { pattern: /exec\(|system\(/g, severity: 'critical', desc: 'Command execution detected' }, - { pattern: /SELECT \* FROM/gi, severity: 'medium', desc: 'SELECT * query (performance concern)' }, - { pattern: /cors.*origin.*\*/g, severity: 'high', desc: 'CORS wildcard origin' }, - ]; - for (const { pattern, severity, desc } of criticalPatterns) { - if (pattern.test(diff)) { - risks.push({ - severity, - category: 'security', - description: desc, - }); - } - } - // Check for breaking changes - if (diff.includes('BREAKING CHANGE') || diff.includes('breaking:')) { - risks.push({ - severity: 'high', - category: 'breaking-change', - description: 'Breaking change mentioned in commit message', - }); - } - // Sort by severity - const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 }; - risks.sort((a, b) => severityOrder[a.severity] - - severityOrder[b.severity]); - return JSON.stringify({ - totalRisks: risks.length, - critical: risks.filter((r) => r.severity === 'critical').length, - high: risks.filter((r) => r.severity === 'high').length, - medium: risks.filter((r) => r.severity === 'medium').length, - risks: risks.slice(0, 10), // Top 10 risks - recommendation: risks.length === 0 - ? 'No significant risks detected' - : risks.length > 5 - ? 'Careful review recommended - multiple risks detected' - : 'Review recommended for identified risks', - }); - }, -}); -/** - * Generate recommendations based on analysis - */ -exports.generateRecommendationsTool = new tools_1.DynamicStructuredTool({ - name: 'generate_recommendations', - description: `Generate actionable recommendations based on the analysis results. - Use this at the end to provide constructive feedback.`, - schema: zod_1.z.object({ - analysisResults: zod_1.z.string().describe('JSON string of all analysis results'), - overallComplexity: zod_1.z.number().describe('Overall complexity score (1-5)'), - }), - func: async ({ analysisResults, overallComplexity }) => { - const recommendations = []; - const results = JSON.parse(analysisResults); - // Recommendations based on complexity - if (overallComplexity >= 4) { - recommendations.push('Consider breaking this PR into smaller, focused changes'); - recommendations.push('Add comprehensive tests for high-complexity areas'); - } - // Recommendations based on risks - if (results.risks && results.risks.length > 0) { - recommendations.push('Address identified security concerns before merging'); - if (results.risks.some((r) => r.severity === 'critical')) { - recommendations.push('CRITICAL: Review and fix critical security issues immediately'); - } - } - // Recommendations based on patterns - if (results.patterns) { - if (results.patterns.includes('Database schema changes')) { - recommendations.push('Ensure database migrations are reversible'); - recommendations.push('Test migration on staging environment'); - } - if (results.patterns.includes('API routes modified')) { - recommendations.push('Update API documentation'); - recommendations.push('Verify backward compatibility'); - } - } - // General recommendations - if (results.testFiles === 0) { - recommendations.push('Consider adding tests for the changes'); - } - if (recommendations.length === 0) { - recommendations.push('Changes look good - ready for review'); - recommendations.push('Consider adding descriptive comments for complex logic'); - } - return JSON.stringify({ - recommendations, - priority: overallComplexity >= 4 || (results.risks && results.risks.length > 5) - ? 'high' - : 'normal', - }); - }, -}); -/** - * Helper function to detect programming language from file path - */ -function detectLanguage(filePath) { - const ext = filePath.split('.').pop()?.toLowerCase(); - const languageMap = { - ts: 'TypeScript', - tsx: 'TypeScript React', - js: 'JavaScript', - jsx: 'JavaScript React', - py: 'Python', - java: 'Java', - go: 'Go', - rs: 'Rust', - cpp: 'C++', - c: 'C', - cs: 'C#', - rb: 'Ruby', - php: 'PHP', - swift: 'Swift', - kt: 'Kotlin', - sql: 'SQL', - yml: 'YAML', - yaml: 'YAML', - json: 'JSON', - md: 'Markdown', - css: 'CSS', - scss: 'SCSS', - html: 'HTML', - }; - return languageMap[ext || ''] || 'Unknown'; -} -/** - * Export all tools as an array - */ -exports.prAnalysisTools = [ - exports.parseDiffTool, - exports.analyzeFileTool, - exports.detectPatternsTool, - exports.assessRisksTool, - exports.generateRecommendationsTool, -]; -//# sourceMappingURL=tools.js.map \ No newline at end of file diff --git a/dist/agent/tools.js.map b/dist/agent/tools.js.map deleted file mode 100644 index df09753..0000000 --- a/dist/agent/tools.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/agent/tools.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/agent/workflow.d.ts b/dist/agent/workflow.d.ts deleted file mode 100644 index ccfe738..0000000 --- a/dist/agent/workflow.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * LangGraph Agent Workflow for PR Analysis - * Defines the agent nodes and graph structure - */ -/** - * Create the agent executor with LangGraph - */ -export declare function createPRAnalysisAgent(apiKey: string, model?: string): Promise>; diff --git a/dist/agent/workflow.js b/dist/agent/workflow.js deleted file mode 100644 index 27e1b5e..0000000 --- a/dist/agent/workflow.js +++ /dev/null @@ -1,222 +0,0 @@ -"use strict"; -/** - * LangGraph Agent Workflow for PR Analysis - * Defines the agent nodes and graph structure - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createPRAnalysisAgent = createPRAnalysisAgent; -const anthropic_1 = require("@langchain/anthropic"); -const langgraph_1 = require("@langchain/langgraph"); -const prebuilt_1 = require("@langchain/langgraph/prebuilt"); -const state_1 = require("./state"); -const tools_1 = require("./tools"); -/** - * Create the agent executor with LangGraph - */ -async function createPRAnalysisAgent(apiKey, model = 'claude-sonnet-4-5-20250929') { - // Initialize the LLM with tools - const llm = new anthropic_1.ChatAnthropic({ - anthropicApiKey: apiKey, - modelName: model, - temperature: 0.2, - maxTokens: 4096, - }); - // Bind tools to the LLM - const llmWithTools = llm.bindTools(tools_1.prAnalysisTools); - /** - * Plan Node: Determine analysis strategy - */ - async function planNode(state) { - const reasoning = []; - let strategy = 'comprehensive'; - // Determine strategy based on diff size and complexity - const diffSize = state.diff.length; - const fileCount = (state.diff.match(/^diff --git /gm) || []).length; - if (diffSize < 5000 && fileCount <= 3) { - strategy = 'quick'; - reasoning.push(`Quick analysis: Small PR with ${fileCount} files, ${diffSize} bytes`); - } - else if (diffSize > 50000 || fileCount > 20) { - strategy = 'deep-dive'; - reasoning.push(`Deep-dive analysis: Large PR with ${fileCount} files, ${diffSize} bytes`); - } - else { - strategy = 'comprehensive'; - reasoning.push(`Comprehensive analysis: Medium PR with ${fileCount} files, ${diffSize} bytes`); - } - return { - strategy, - reasoning, - iterationCount: 1, - }; - } - /** - * Agent Node: The main reasoning agent that decides which tools to call - */ - async function agentNode(state) { - const messages = []; - // Build context message - let systemPrompt = `You are an expert code reviewer analyzing a pull request. - -Your goal is to: -1. Parse the diff to understand what changed -2. Analyze files for complexity and risks -3. Detect patterns and architectural changes -4. Assess overall risks -5. Generate actionable recommendations - -Available tools: -- parse_diff: Parse git diff into structured file changes -- analyze_file: Deep-dive into specific files -- detect_patterns: Identify design patterns and architecture -- assess_risks: Evaluate security and breaking changes -- generate_recommendations: Create actionable feedback - -Strategy: ${state.strategy} -Analysis mode: ${JSON.stringify(state.mode)} - -Start by parsing the diff, then analyze important files, detect patterns, assess risks, and finally generate recommendations.`; - messages.push({ - role: 'system', - content: systemPrompt, - }); - // Add user message with the diff - const userMessage = `Please analyze this pull request${state.title ? ` titled "${state.title}"` : ''}: - -\`\`\`diff -${state.diff.substring(0, 50000)}${state.diff.length > 50000 ? '\n... (diff truncated)' : ''} -\`\`\` - -${state.parsedFiles.length > 0 ? `\nParsed files: ${JSON.stringify(state.parsedFiles.map((f) => ({ path: f.path, status: f.status, changes: f.additions + f.deletions })))}` : ''} -${state.fileAnalyses.length > 0 ? `\nFile analyses completed: ${state.fileAnalyses.length}` : ''} -${state.designPatterns.length > 0 ? `\nPatterns detected: ${state.designPatterns.join(', ')}` : ''} - -${state.parsedFiles.length === 0 ? 'Start by using parse_diff to understand the changes.' : ''} -${state.parsedFiles.length > 0 && state.fileAnalyses.length === 0 ? 'Now analyze key files using analyze_file.' : ''} -${state.fileAnalyses.length > 0 && state.designPatterns.length === 0 ? 'Now detect patterns using detect_patterns.' : ''} -${state.designPatterns.length > 0 && state.overallRisks.length === 0 ? 'Now assess risks using assess_risks.' : ''} -${state.overallRisks.length > 0 && state.recommendations.length === 0 ? 'Finally, generate recommendations using generate_recommendations.' : ''} -`; - messages.push({ - role: 'user', - content: userMessage, - }); - // Invoke the LLM with tools - const response = await llmWithTools.invoke(messages); - return { - reasoning: [`Agent decision: ${response.content}`], - tokensUsed: response.usage_metadata?.total_tokens || 0, - }; - } - /** - * Tool Node: Executes the tools the agent decided to call - */ - const toolNode = new prebuilt_1.ToolNode(tools_1.prAnalysisTools); - /** - * Synthesis Node: Combine all analysis results into final output - */ - async function synthesisNode(state) { - const messages = [ - { - role: 'system', - content: `You are synthesizing a PR analysis. Create a comprehensive summary based on all the analysis results.`, - }, - { - role: 'user', - content: `Based on the analysis: - -Files analyzed: ${state.fileAnalyses.length} -Patterns: ${state.designPatterns.join(', ')} -Risks: ${state.overallRisks.length} identified -Architecture changes: ${state.architecturalChanges.join(', ')} - -${state.mode.summary ? 'Generate a clear, concise summary of the changes and their impact.' : ''} -${state.mode.complexity ? 'Calculate an overall complexity score (1-5).' : ''} -${state.mode.risks ? 'Summarize the key risks.' : ''} - -Provide your response in JSON format: -{ - "summary": "...", - "overallComplexity": 1-5, - "keyInsights": ["..."], - "criticalRisks": ["..."] -}`, - }, - ]; - const response = await llm.invoke(messages); - const content = response.content.toString(); - // Try to parse JSON response - let result; - try { - const jsonMatch = content.match(/\{[\s\S]*\}/); - if (jsonMatch) { - result = JSON.parse(jsonMatch[0]); - } - } - catch (e) { - // Fallback if JSON parsing fails - result = { - summary: content, - overallComplexity: Math.min(5, Math.max(1, Math.ceil(state.fileAnalyses.length / 5))), - keyInsights: [], - criticalRisks: [], - }; - } - return { - summary: result.summary || 'Analysis completed', - overallComplexity: result.overallComplexity || 3, - insights: result.keyInsights || [], - completed: true, - tokensUsed: response.usage_metadata?.total_tokens || 0, - }; - } - /** - * Router: Determine next step based on state - */ - function routeAgent(state) { - // If we haven't parsed files yet, continue with agent - if (state.parsedFiles.length === 0) { - return 'agent'; - } - // If we have parsed files but no analyses, continue - if (state.fileAnalyses.length === 0) { - return 'agent'; - } - // If we have analyses but no patterns, continue - if (state.designPatterns.length === 0) { - return 'agent'; - } - // If we have patterns but no risk assessment, continue - if (state.overallRisks.length === 0) { - return 'agent'; - } - // If we have risks but no recommendations, continue - if (state.recommendations.length === 0) { - return 'agent'; - } - // All analysis complete, move to synthesis - return 'synthesis'; - } - /** - * Build the LangGraph workflow - */ - const workflow = new langgraph_1.StateGraph(state_1.PRAgentState) - // Add nodes - .addNode('plan', planNode) - .addNode('agent', agentNode) - .addNode('tools', toolNode) - .addNode('synthesis', synthesisNode) - // Define edges - .addEdge('__start__', 'plan') - .addEdge('plan', 'agent') - .addConditionalEdges('agent', routeAgent, { - agent: 'agent', - synthesis: 'synthesis', - }) - .addEdge('tools', 'agent') - .addEdge('synthesis', langgraph_1.END); - // Compile the graph - const app = workflow.compile(); - return app; -} -//# sourceMappingURL=workflow.js.map \ No newline at end of file diff --git a/dist/agent/workflow.js.map b/dist/agent/workflow.js.map deleted file mode 100644 index a154d53..0000000 --- a/dist/agent/workflow.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/agent/workflow.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/agents/base-pr-agent-workflow.d.ts b/dist/agents/base-pr-agent-workflow.d.ts index b04e6c5..3e7ad41 100644 --- a/dist/agents/base-pr-agent-workflow.d.ts +++ b/dist/agents/base-pr-agent-workflow.d.ts @@ -4,8 +4,7 @@ */ import { MemorySaver } from '@langchain/langgraph'; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; -import { AgentContext, AgentResult, FileAnalysis, AgentExecutionOptions } from '../types/agent.types.js'; -import { SemgrepResult, SemgrepSummary } from '../types/semgrep.types.js'; +import { AgentContext, AgentResultOrPrompts, FileAnalysis, AgentExecutionOptions, ExecutionMode } from '../types/agent.types.js'; /** * Agent workflow state */ @@ -14,17 +13,8 @@ export declare const PRAgentState: import("@langchain/langgraph").AnnotationRoot iteration: import("@langchain/langgraph").BinaryOperatorAggregate; fileAnalyses: import("@langchain/langgraph").BinaryOperatorAggregate, Map>; currentSummary: import("@langchain/langgraph").BinaryOperatorAggregate; - fixes: import("@langchain/langgraph").BinaryOperatorAggregate<{ - file: string; - line?: number; - comment: string; - severity?: "critical" | "warning" | "suggestion"; - }[], { - file: string; - line?: number; - comment: string; - severity?: "critical" | "warning" | "suggestion"; - }[]>; + currentRisks: import("@langchain/langgraph").BinaryOperatorAggregate; + currentComplexity: import("@langchain/langgraph").BinaryOperatorAggregate; clarityScore: import("@langchain/langgraph").BinaryOperatorAggregate; missingInformation: import("@langchain/langgraph").BinaryOperatorAggregate; recommendations: import("@langchain/langgraph").BinaryOperatorAggregate; @@ -34,39 +24,69 @@ export declare const PRAgentState: import("@langchain/langgraph").AnnotationRoot archDocsKeyInsights: import("@langchain/langgraph").BinaryOperatorAggregate; totalInputTokens: import("@langchain/langgraph").BinaryOperatorAggregate; totalOutputTokens: import("@langchain/langgraph").BinaryOperatorAggregate; - semgrepResult: import("@langchain/langgraph").BinaryOperatorAggregate; - semgrepSummary: import("@langchain/langgraph").BinaryOperatorAggregate; }>; /** * Configuration for PR agent workflow */ export interface PRAgentWorkflowConfig { + maxIterations: number; + clarityThreshold: number; skipSelfRefinement?: boolean; } /** * Base class for PR agents with self-refinement workflow */ export declare abstract class BasePRAgentWorkflow { - protected model: BaseChatModel; - protected workflow: ReturnType; + protected model?: BaseChatModel; + protected mode: ExecutionMode; + protected workflow?: ReturnType; protected checkpointer: MemorySaver; protected tools: any[]; - constructor(model: BaseChatModel); + constructor(mode?: ExecutionMode, model?: BaseChatModel); /** * Build the PR analysis workflow */ private buildWorkflow; /** * Execute the agent workflow + * Routes to either EXECUTE mode (run analysis) or PROMPT_ONLY mode (return prompts) */ - execute(context: AgentContext, options?: AgentExecutionOptions): Promise; + execute(context: AgentContext, options?: AgentExecutionOptions): Promise; + /** + * Build all prompts for PROMPT_ONLY mode (without executing them) + * Also runs static analysis tools that don't require an LLM + */ + private buildAllPrompts; + /** + * Build file analysis prompt + */ + private buildFileAnalysisPrompt; + /** + * Build risk detection prompt + */ + private buildRiskDetectionPrompt; + /** + * Build summary generation prompt + */ + private buildSummaryPrompt; + /** + * Execute the agent workflow in EXECUTE mode (with LLM) + */ + private executeAnalysis; /** * Fast path execution - skip refinement loop but still use LLM for detailed analysis */ private executeFastPath; + /** + * Smart change detection - analyzes files and returns only relevant enhanced features + */ + private detectAndAnalyzeChangeTypes; private analyzeFilesNode; - private runStaticAnalysisNode; - private generateFixesNode; + private detectRisksNode; + private calculateComplexityNode; private generateSummaryNode; + private evaluateQualityNode; + private refineAnalysisNode; private finalizeNode; + private shouldRefine; } diff --git a/dist/agents/base-pr-agent-workflow.js b/dist/agents/base-pr-agent-workflow.js index 3baaa20..fa41f9d 100644 --- a/dist/agents/base-pr-agent-workflow.js +++ b/dist/agents/base-pr-agent-workflow.js @@ -4,10 +4,16 @@ */ import { StateGraph, Annotation, END } from '@langchain/langgraph'; import { MemorySaver } from '@langchain/langgraph'; +import { ExecutionMode, } from '../types/agent.types.js'; +import path from 'path'; import { parseDiff, createFileAnalyzerTool, createRiskDetectorTool, createComplexityScorerTool, createSummaryGeneratorTool, } from '../tools/pr-analysis-tools.js'; import { formatArchDocsForPrompt, getSecurityContext, getPatternsContext } from '../utils/arch-docs-rag.js'; import { parseAllArchDocs } from '../utils/arch-docs-parser.js'; -import { runSemgrepAnalysis, summarizeSemgrepFindings, filterFindingsByChangedFiles } from '../utils/semgrep-runner.js'; +import { isTestFile, isCodeFile, detectTestFramework, generateTestTemplate, suggestTestFilePath, analyzeTestQuality, } from '../tools/test-suggestion-tool.js'; +import { isDevOpsFile, analyzeDevOpsFiles, } from '../tools/devops-cost-estimator.js'; +import { detectCoverageTool, readCoverageReport, } from '../tools/coverage-reporter.js'; +import { classifyProject, formatClassification, } from '../tools/project-classifier.js'; +import { getProjectClassification } from '../db/index.js'; /** * Agent workflow state */ @@ -31,10 +37,14 @@ export const PRAgentState = Annotation.Root({ reducer: (_, update) => update, default: () => '', }), - fixes: Annotation({ + currentRisks: Annotation({ reducer: (_, update) => update, default: () => [], }), + currentComplexity: Annotation({ + reducer: (_, update) => update, + default: () => 1, + }), // Quality metrics clarityScore: Annotation({ reducer: (_, update) => update, @@ -76,26 +86,23 @@ export const PRAgentState = Annotation.Root({ reducer: (current, update) => current + update, default: () => 0, }), - // Semgrep static analysis - semgrepResult: Annotation({ - reducer: (_, update) => update, - default: () => null, - }), - semgrepSummary: Annotation({ - reducer: (_, update) => update, - default: () => null, - }), }); /** * Base class for PR agents with self-refinement workflow */ export class BasePRAgentWorkflow { - model; - workflow; + model; // Now optional! + mode; + workflow; // Optional in PROMPT_ONLY mode checkpointer = new MemorySaver(); tools; - constructor(model) { + constructor(mode = ExecutionMode.EXECUTE, model) { + this.mode = mode; this.model = model; + // Validation: LLM required in EXECUTE mode + if (mode === ExecutionMode.EXECUTE && !model) { + throw new Error('BasePRAgentWorkflow: LLM is required when mode is EXECUTE'); + } // Initialize tools this.tools = [ createFileAnalyzerTool(), @@ -103,45 +110,248 @@ export class BasePRAgentWorkflow { createComplexityScorerTool(), createSummaryGeneratorTool(), ]; - this.workflow = this.buildWorkflow(); + // Only build workflow in EXECUTE mode + if (mode === ExecutionMode.EXECUTE) { + this.workflow = this.buildWorkflow(); + } } /** * Build the PR analysis workflow */ buildWorkflow() { const graph = new StateGraph(PRAgentState); - // Define nodes - simplified workflow + // Define nodes graph.addNode('analyzeFiles', this.analyzeFilesNode.bind(this)); - graph.addNode('runStaticAnalysis', this.runStaticAnalysisNode.bind(this)); - graph.addNode('generateFixes', this.generateFixesNode.bind(this)); + graph.addNode('detectRisks', this.detectRisksNode.bind(this)); + graph.addNode('calculateComplexity', this.calculateComplexityNode.bind(this)); graph.addNode('generateSummary', this.generateSummaryNode.bind(this)); + graph.addNode('evaluateQuality', this.evaluateQualityNode.bind(this)); + graph.addNode('refineAnalysis', this.refineAnalysisNode.bind(this)); graph.addNode('finalize', this.finalizeNode.bind(this)); // Set entry point const entryPoint = 'analyzeFiles'; graph.setEntryPoint(entryPoint); - // Build simplified linear workflow graph - graph.addEdge(entryPoint, 'runStaticAnalysis'); - graph.addEdge('runStaticAnalysis', 'generateFixes'); - graph.addEdge('generateFixes', 'generateSummary'); - graph.addEdge('generateSummary', 'finalize'); + // Build workflow graph + graph.addEdge(entryPoint, 'detectRisks'); + graph.addEdge('detectRisks', 'calculateComplexity'); + graph.addEdge('calculateComplexity', 'generateSummary'); + graph.addEdge('generateSummary', 'evaluateQuality'); + // Conditional: refine or finalize + graph.addConditionalEdges('evaluateQuality', this.shouldRefine.bind(this), { + refine: 'refineAnalysis', + finalize: 'finalize', + }); + // After refinement, evaluate again + graph.addEdge('refineAnalysis', 'evaluateQuality'); + // End after finalization graph.addEdge('finalize', END); return graph.compile({ checkpointer: this.checkpointer }); } /** * Execute the agent workflow + * Routes to either EXECUTE mode (run analysis) or PROMPT_ONLY mode (return prompts) */ async execute(context, options) { + if (this.mode === ExecutionMode.PROMPT_ONLY) { + return await this.buildAllPrompts(context); + } + else { + return this.executeAnalysis(context, options); + } + } + /** + * Build all prompts for PROMPT_ONLY mode (without executing them) + * Also runs static analysis tools that don't require an LLM + */ + async buildAllPrompts(context) { + const files = parseDiff(context.diff); + const prompts = []; + // Build arch-docs context if available + let archDocsContext = ''; + if (context.archDocs?.available) { + archDocsContext = formatArchDocsForPrompt(context.archDocs); + } + // === RUN STATIC ANALYSIS (no LLM needed) === + // These features run immediately and results are included in the output + console.log('🔧 Running static analysis tools...'); + const staticAnalysis = await this.detectAndAnalyzeChangeTypes(files, context); + console.log(`✅ Static analysis complete`); + // 1. File Analysis Prompts (for important files) + const filesToAnalyze = files.slice(0, 15); + const importantFiles = filesToAnalyze.filter(f => f.additions + f.deletions > 20 || + f.path.includes('config') || + f.path.includes('schema') || + f.path.includes('migration') || + f.path.includes('test')).slice(0, 5); + if (importantFiles.length > 0) { + prompts.push(this.buildFileAnalysisPrompt(importantFiles, archDocsContext)); + } + // 2. Risk Detection Prompt + prompts.push(this.buildRiskDetectionPrompt(files, archDocsContext, context)); + // 3. Summary Generation Prompt + prompts.push(this.buildSummaryPrompt(files, archDocsContext, context)); + // 4. Self Refinement Prompt (placeholder - would need analysis results) + // Note: This would typically need results from previous steps + // For now, we'll skip it in PROMPT_ONLY mode or make it conditional + return { + mode: 'prompt_only', + context, + prompts, + // Include static analysis results + staticAnalysis, + instructions: `Execute these prompts sequentially using your LLM: +1. First, analyze the important files in the PR +2. Then detect risks and security issues +3. Generate an overall PR summary +4. (Optional) Refine the analysis based on results + +Each prompt includes the necessary context and instructions for execution. + +Note: Static analysis (test suggestions, DevOps costs, coverage reports) has already been run and is included below.` + }; + } + /** + * Build file analysis prompt + */ + buildFileAnalysisPrompt(importantFiles, archDocsContext) { + const prompt = `Analyze these files from a pull request. For EACH file, provide a detailed analysis considering the repository's architecture standards. +${archDocsContext ? '\n' + archDocsContext : ''} + +Files to analyze: +${importantFiles.map(f => ` +File: ${f.path} +Status: ${f.status || 'modified'} +Changes: +${f.additions} -${f.deletions} +Diff preview: +\`\`\` +${f.diff.substring(0, 500)} +\`\`\` +`).join('\n---\n')} + +${archDocsContext ? `CRITICAL INSTRUCTIONS: +- For EACH file, reference the relevant architecture documentation sections above +- Explain how the changes align with or diverge from established patterns +- Identify specific guidelines that apply to each file +- Mention which parts of the architecture are affected +- Compare changes against documented standards + +` : ''} + +Respond with a JSON object mapping file paths to analysis objects: +{ + "path/to/file": { + "summary": "Description that references relevant arch-docs patterns/guidelines", + "risks": ["risk with arch-docs context", "risk2"], + "complexity": 1-5, + "recommendations": ["recommendation based on arch-docs standards"] + } +} + +${archDocsContext ? 'Each summary MUST reference the specific architecture documentation that applies to this file.' : ''}`; + return { + step: 'fileAnalysis', + prompt, + context: { fileCount: importantFiles.length }, + instructions: 'Analyze each file and return JSON object with file analyses' + }; + } + /** + * Build risk detection prompt + */ + buildRiskDetectionPrompt(files, archDocsContext, context) { + const prompt = `Review this pull request for potential risks, security issues, and code quality problems. + +${archDocsContext ? archDocsContext : ''} + +Files changed (${files.length} total): +${files.map(f => `- ${f.path} (+${f.additions}/-${f.deletions})`).join('\n')} + +Full diff: +\`\`\`diff +${context.diff.substring(0, 8000)} +\`\`\` + +${archDocsContext ? `You have access to architecture documentation. Reference relevant security guidelines when identifying risks. + +Return a JSON array of risk objects with archDocsSource and archDocsExcerpt: +[ + { + "file": "path/to/file", + "line": 42, + "comment": "Description of risk", + "severity": "critical|warning|suggestion", + "archDocsSource": "security.md", + "archDocsExcerpt": "Relevant excerpt from arch-docs", + "reason": "Why this is a risk based on arch-docs" + } +] + +DO NOT return simple string arrays. Each risk MUST be an object with archDocsSource, archDocsExcerpt, and reason fields.` : '["risk 1", "risk 2", ...]'} + +Only include risks that are actually present. If no significant risks, return an empty array [].`; + return { + step: 'riskDetection', + prompt, + context: { fileCount: files.length }, + instructions: 'Detect risks and return JSON array of risk objects' + }; + } + /** + * Build summary generation prompt + */ + buildSummaryPrompt(files, archDocsContext, context) { + const prompt = `Generate a comprehensive summary of this pull request. + +${archDocsContext ? archDocsContext : ''} + +PR Title: ${context.title || 'Untitled PR'} + +Files changed: ${files.length} +Total additions: +${files.reduce((sum, f) => sum + f.additions, 0)} +Total deletions: -${files.reduce((sum, f) => sum + f.deletions, 0)} + +Key files: +${files.slice(0, 10).map(f => `- ${f.path} (+${f.additions}/-${f.deletions})`).join('\n')} + +Diff excerpt: +\`\`\`diff +${context.diff.substring(0, 5000)} +\`\`\` + +${archDocsContext ? 'Consider the design patterns and architecture from the repository documentation when analyzing the changes.\n' : ''} + +Provide a detailed, well-structured summary (3-5 paragraphs) that would help a reviewer understand the scope and purpose of this PR.`; + return { + step: 'summaryGeneration', + prompt, + context: {}, + instructions: 'Generate detailed PR summary (3-5 paragraphs)' + }; + } + /** + * Execute the agent workflow in EXECUTE mode (with LLM) + */ + async executeAnalysis(context, options) { + if (!this.workflow) { + throw new Error('Workflow not initialized - executeAnalysis should only be called in EXECUTE mode'); + } const startTime = Date.now(); // Fast path: skip self-refinement if (options?.skipSelfRefinement) { return this.executeFastPath(context, startTime); } + const config = { + maxIterations: 3, + clarityThreshold: 80, + skipSelfRefinement: false, + }; const initialState = { context, iteration: 0, fileAnalyses: new Map(), currentSummary: '', - fixes: [], + currentRisks: [], + currentComplexity: 1, clarityScore: 0, missingInformation: [], recommendations: [], @@ -149,14 +359,12 @@ export class BasePRAgentWorkflow { reasoning: [], totalInputTokens: 0, totalOutputTokens: 0, - semgrepResult: null, - semgrepSummary: null, - archDocsInfluencedStages: [], - archDocsKeyInsights: [], }; const workflowConfig = { configurable: { thread_id: `pr-agent-${Date.now()}`, + maxIterations: config.maxIterations, + clarityThreshold: config.clarityThreshold, }, recursionLimit: 50, }; @@ -196,18 +404,32 @@ export class BasePRAgentWorkflow { influencedStages: [...new Set(stateAny.archDocsInfluencedStages || [])], keyInsights: [...new Set(stateAny.archDocsKeyInsights || [])], } : undefined; - // Build static analysis summary - const staticAnalysis = stateAny.semgrepSummary ? { - enabled: true, - totalFindings: stateAny.semgrepSummary.totalFindings, - errorCount: stateAny.semgrepSummary.errorCount, - warningCount: stateAny.semgrepSummary.warningCount, - criticalIssues: stateAny.semgrepSummary.criticalFindings.map((f) => f.extra.message).slice(0, 5), - } : undefined; + // Smart change detection - only include relevant outputs + const files = parseDiff(context.diff); + const enhancedResult = await this.detectAndAnalyzeChangeTypes(files, context); + // Convert currentRisks to fixes format for backward compatibility + const fixes = finalState.currentRisks.map((risk) => { + // Risk can be a string or RiskItem object + if (typeof risk === 'string') { + return { + file: '', + comment: risk, + severity: 'warning', + }; + } + return { + file: risk.file || '', + line: risk.line, + comment: risk.description || risk.reason || String(risk), + severity: risk.severity || 'warning', + }; + }); return { summary: finalState.currentSummary, fileAnalyses: finalState.fileAnalyses, - fixes: finalState.fixes, + fixes, + overallComplexity: finalState.currentComplexity, + overallRisks: finalState.currentRisks, recommendations: finalState.recommendations, insights: finalState.insights, reasoning: finalState.reasoning, @@ -217,7 +439,8 @@ export class BasePRAgentWorkflow { executionTime, mode: context.mode, archDocsImpact, - staticAnalysis, + // Conditionally include new features based on change types + ...enhancedResult, }; } /** @@ -230,7 +453,8 @@ export class BasePRAgentWorkflow { iteration: 0, fileAnalyses: new Map(), currentSummary: '', - fixes: [], + currentRisks: [], + currentComplexity: 1, clarityScore: 0, missingInformation: [], recommendations: [], @@ -238,21 +462,21 @@ export class BasePRAgentWorkflow { reasoning: [], totalInputTokens: 0, totalOutputTokens: 0, - semgrepResult: null, - semgrepSummary: null, }; // Execute workflow nodes sequentially (skip refinement loop) let state = initialState; try { // 1. Analyze files state = await this.analyzeFilesNode(state); - // 2. Run static analysis - state = await this.runStaticAnalysisNode(state); - // 3. Generate fixes - state = await this.generateFixesNode(state); + // 2. Detect risks + state = await this.detectRisksNode(state); + // 3. Calculate complexity + state = await this.calculateComplexityNode(state); // 4. Generate summary state = await this.generateSummaryNode(state); - // 5. Finalize (includes recommendations) + // 5. Generate recommendations (skip quality evaluation) + state = await this.refineAnalysisNode(state); + // 6. Finalize state = await this.finalizeNode(state); const executionTime = Date.now() - startTime; // Build arch-docs impact summary with deduplication @@ -264,18 +488,32 @@ export class BasePRAgentWorkflow { influencedStages: [...new Set(stateAny.archDocsInfluencedStages || [])], keyInsights: [...new Set(stateAny.archDocsKeyInsights || [])], } : undefined; - // Build static analysis summary - const staticAnalysis = state.semgrepSummary ? { - enabled: true, - totalFindings: state.semgrepSummary.totalFindings, - errorCount: state.semgrepSummary.errorCount, - warningCount: state.semgrepSummary.warningCount, - criticalIssues: state.semgrepSummary.criticalFindings.map((f) => f.extra.message).slice(0, 5), - } : undefined; + // Smart change detection - only include relevant outputs + const files = parseDiff(context.diff); + const enhancedResult = await this.detectAndAnalyzeChangeTypes(files, context); + // Convert currentRisks to fixes format for backward compatibility + const fixes = state.currentRisks.map((risk) => { + // Risk can be a string or RiskItem object + if (typeof risk === 'string') { + return { + file: '', + comment: risk, + severity: 'warning', + }; + } + return { + file: risk.file || '', + line: risk.line, + comment: risk.description || risk.reason || String(risk), + severity: risk.severity || 'warning', + }; + }); return { summary: state.currentSummary, fileAnalyses: state.fileAnalyses, - fixes: state.fixes, + fixes, + overallComplexity: state.currentComplexity, + overallRisks: state.currentRisks, recommendations: state.recommendations, insights: state.insights, reasoning: [...state.reasoning, 'Fast path: Self-refinement evaluation skipped for speed'], @@ -285,7 +523,8 @@ export class BasePRAgentWorkflow { executionTime, mode: context.mode, archDocsImpact, - staticAnalysis, + // Conditionally include new features based on change types + ...enhancedResult, }; } catch (error) { @@ -293,6 +532,118 @@ export class BasePRAgentWorkflow { throw error; } } + /** + * Smart change detection - analyzes files and returns only relevant enhanced features + */ + async detectAndAnalyzeChangeTypes(files, context) { + const result = {}; + // === PROJECT CLASSIFICATION === + // Check DB cache first, only run classification if not cached (saves tokens) + const repoOwner = context.config?.repoOwner || 'local'; + const repoName = context.config?.repoName || 'unknown'; + let cachedClassification = getProjectClassification(repoOwner, repoName); + if (cachedClassification) { + // Use cached classification + result.projectClassification = cachedClassification; + } + else { + // Run classification and store for caching + const classification = classifyProject(files.map(f => ({ filename: f.path, patch: f.diff }))); + result.projectClassification = formatClassification(classification); + } + // Categorize files by type + const codeFiles = files.filter(f => isCodeFile(f.path) && !isTestFile(f.path)); + const testFiles = files.filter(f => isTestFile(f.path)); + const devOpsFiles = files.filter(f => isDevOpsFile(f.path).isDevOps); + console.log(`📊 Change Analysis: ${codeFiles.length} code files, ${testFiles.length} test files, ${devOpsFiles.length} DevOps files`); + // 1. Developer changes without tests → Test Suggestions + if (codeFiles.length > 0 && codeFiles.length > testFiles.length) { + console.log(`🧪 Detecting test suggestions for ${codeFiles.length} code files...`); + const frameworkInfo = detectTestFramework(context.config?.repoPath || '.'); + const testSuggestions = []; + for (const file of codeFiles) { + // Check if there's a corresponding test file in the PR + const baseName = file.path.replace(/\.[^/.]+$/, '').split('/').pop() || ''; + const hasTest = testFiles.some(t => t.path.toLowerCase().includes(baseName.toLowerCase())); + if (!hasTest && file.additions > 5) { + // Extract function names from diff for better test generation + const functionMatches = file.diff.match(/(?:function|const|let|var|async)\s+(\w+)/g) || []; + const functionNames = functionMatches + .map(m => m.replace(/(?:function|const|let|var|async)\s+/, '')) + .filter(name => name.length > 2 && !['the', 'and', 'for'].includes(name)); + const testCode = generateTestTemplate(frameworkInfo.framework, file.path, file.diff, functionNames.slice(0, 5)); + testSuggestions.push({ + forFile: file.path, + testFramework: frameworkInfo.framework, + testCode, + description: `Suggested tests for new/modified code in ${file.path}`, + testFilePath: suggestTestFilePath(file.path, frameworkInfo.framework), + }); + } + } + if (testSuggestions.length > 0) { + result.testSuggestions = testSuggestions; + console.log(`✅ Generated ${testSuggestions.length} test suggestions`); + } + } + // 1b. Existing tests → Test Enhancement Suggestions + if (testFiles.length > 0 && codeFiles.length > 0) { + console.log(`🔬 Analyzing ${testFiles.length} existing test file(s) for improvements...`); + const frameworkInfo = detectTestFramework(context.config?.repoPath || '.'); + for (const testFile of testFiles) { + // Find corresponding source file + const baseName = testFile.path + .replace(/\.(test|spec)\./i, '.') + .replace(/^(test|tests|__tests__)\//i, '') + .replace(/\/(test|tests|__tests__)\//i, '/'); + const sourceFile = codeFiles.find(f => f.path.includes(baseName.split('/').pop()?.replace(/\.[^.]+$/, '') || '')); + if (sourceFile && testFile.additions > 0) { + // Analyze test quality and suggest enhancements + const enhancement = analyzeTestQuality({ path: testFile.path, diff: testFile.diff }, { path: sourceFile.path, diff: sourceFile.diff }, frameworkInfo.framework); + if (enhancement.suggestions.length > 0) { + // Add as test suggestion with enhancement flag + result.testSuggestions = result.testSuggestions || []; + result.testSuggestions.push({ + forFile: sourceFile.path, + testFramework: frameworkInfo.framework, + testCode: enhancement.enhancementCode || '', + description: `Test enhancements for ${path.basename(testFile.path)}: ${enhancement.suggestions.join(', ')}`, + testFilePath: testFile.path, + isEnhancement: true, + existingTestFile: testFile.path, + }); + console.log(` → Found ${enhancement.missingScenarios.length} missing scenario(s) in ${path.basename(testFile.path)}`); + } + } + } + const enhancementCount = result.testSuggestions?.filter(s => s.isEnhancement).length || 0; + if (enhancementCount > 0) { + console.log(`✅ Generated ${enhancementCount} test enhancement suggestion(s)`); + } + } + // 2. DevOps/IaC changes → Cost Estimation + if (devOpsFiles.length > 0) { + console.log(`💰 Analyzing DevOps costs for ${devOpsFiles.length} files...`); + const costAnalysis = analyzeDevOpsFiles(devOpsFiles); + if (costAnalysis.hasDevOpsChanges && costAnalysis.estimates.length > 0) { + result.devOpsCostEstimates = costAnalysis.estimates; + console.log(`✅ Estimated costs for ${costAnalysis.estimates.length} resources (~$${costAnalysis.totalEstimatedCost.toFixed(2)}/month)`); + } + } + // 3. Test/QA changes → Coverage Report (only if configured) + if (testFiles.length > 0 || codeFiles.length > 0) { + const coverageConfig = detectCoverageTool(context.config?.repoPath || '.'); + if (coverageConfig.configured) { + console.log(`📊 Checking coverage (${coverageConfig.tool} detected)...`); + const coverage = readCoverageReport(context.config?.repoPath || '.'); + if (coverage.available) { + result.coverageReport = coverage; + console.log(`✅ Coverage: ${coverage.overallPercentage?.toFixed(1)}%`); + } + } + } + return result; + } // Workflow nodes async analyzeFilesNode(state) { const { context } = state; @@ -318,6 +669,9 @@ export class BasePRAgentWorkflow { // Get detailed analysis for important files if (importantFiles.length > 0) { try { + if (!this.model) { + throw new Error('LLM is required for file analysis in EXECUTE mode'); + } const fileDetailsPrompt = `Analyze these files from a pull request. For EACH file, provide a detailed analysis considering the repository's architecture standards. ${archDocsContext ? '\n' + archDocsContext : ''} @@ -429,209 +783,213 @@ ${archDocsContext ? 'Each summary MUST reference the specific architecture docum archDocsKeyInsights: archDocsInsights, }; } - async runStaticAnalysisNode(state) { - const { context } = state; - // Skip if static analysis is disabled - if (!context.enableStaticAnalysis) { - console.log('⏭️ Static analysis disabled, skipping...'); - return state; - } - try { - // Get current working directory for analysis - const targetPath = process.cwd(); - // Run Semgrep analysis - const semgrepResult = await runSemgrepAnalysis(targetPath, { - enabled: true, - timeout: 30, - maxFileSize: 1000000, // 1MB - excludePaths: [ - '**/node_modules/**', - '**/dist/**', - '**/build/**', - '**/.git/**', - '**/*.min.js', - '**/*.map', - ], - }, context.language, context.framework); - // Check for errors - if (semgrepResult.errors && semgrepResult.errors.length > 0) { - const hasBlockingError = semgrepResult.errors.some(e => e.level === 'error' && e.type === 'semgrep_not_installed'); - if (hasBlockingError) { - console.log('ℹ️ Semgrep not available, continuing without static analysis'); - return state; - } - } - // Filter findings to only include changed files - const changedFilePaths = context.files.map(f => f.path); - const relevantFindings = filterFindingsByChangedFiles(semgrepResult.results || [], changedFilePaths); - // Create filtered result - const filteredResult = { - ...semgrepResult, - results: relevantFindings, - }; - // Summarize findings - const summary = summarizeSemgrepFindings(filteredResult); - console.log(` Found ${summary.totalFindings} issues (${summary.errorCount} errors, ${summary.warningCount} warnings)`); - return { - ...state, - semgrepResult: filteredResult, - semgrepSummary: summary, - insights: [`Static analysis: ${summary.totalFindings} findings in changed files`], - }; - } - catch (error) { - console.error('Error running static analysis:', error); - return { - ...state, - insights: ['Static analysis encountered an error and was skipped'], - }; - } - } - async generateFixesNode(state) { - const { context, fileAnalyses, semgrepSummary, semgrepResult } = state; - console.log('🔧 Generating fixes...'); - // If static analysis is enabled, convert Semgrep findings to fixes - if (context.enableStaticAnalysis && semgrepResult && semgrepSummary && semgrepSummary.totalFindings > 0) { - console.log(' Converting Semgrep findings to fixes'); - const fixes = semgrepResult.results.map((finding) => ({ - file: finding.path, - line: finding.start.line, - comment: `${finding.extra.severity === 'ERROR' ? '🔴 **Critical**: ' : finding.extra.severity === 'WARNING' ? '🟡 **Warning**: ' : 'ℹ️ '}${finding.extra.message}\n\n**Rule**: ${finding.check_id}${finding.extra.metadata?.cwe ? `\n**CWE**: ${finding.extra.metadata.cwe.join(', ')}` : ''}${finding.extra.metadata?.owasp ? `\n**OWASP**: ${finding.extra.metadata.owasp.join(', ')}` : ''}`, - severity: finding.extra.severity === 'ERROR' ? 'critical' : finding.extra.severity === 'WARNING' ? 'warning' : 'suggestion', - source: 'semgrep', - })); - return { - ...state, - fixes, - insights: [`Generated ${fixes.length} fixes from Semgrep findings`], - }; - } - // Otherwise, do AI-based fix generation - console.log(' Running AI-based fix generation'); - // Parse diff to get file paths and line numbers - const files = parseDiff(context.diff); + async detectRisksNode(state) { + const { context, fileAnalyses } = state; + console.log('⚠️ Detecting risks...'); + // Build context for risk analysis const fileList = Array.from(fileAnalyses.entries()) .slice(0, 15) .map(([path, analysis]) => `${path} (+${analysis.changes.additions} -${analysis.changes.deletions})`) .join('\n'); - // Get diff sample with line numbers - const diffSample = context.diff.substring(0, 12000); + // Get a sample of the diff for risk analysis (limit size) + const diffSample = context.diff.substring(0, 8000); // First 8KB for context // Add security context from arch-docs if available let securityContext = ''; let allDocs = []; + let securityDoc = null; + let patternsDoc = null; if (context.archDocs?.available) { allDocs = parseAllArchDocs(); const secDoc = getSecurityContext(allDocs); if (secDoc) { securityContext = `\n## Security Guidelines from Repository Documentation\n\n${secDoc.substring(0, 3000)}\n`; + securityDoc = allDocs.find(d => d.filename === 'security'); } + // Also get patterns that might indicate risks const patterns = getPatternsContext(allDocs); if (patterns) { securityContext += `\n## Repository Patterns and Best Practices\n\n${patterns.substring(0, 2000)}\n`; + patternsDoc = allDocs.find(d => d.filename === 'patterns'); } } - const fixesPrompt = `You are a code reviewer analyzing a pull request. Generate CRUCIAL, actionable fixes as PR comments. + const riskPrompt = `You are a security and code quality expert analyzing a pull request for potential risks. ${securityContext} -Analyze the following changes and identify issues that NEED to be fixed. Focus on: -1. **Security Issues**: Exposed credentials, insecure patterns, authentication/authorization problems -2. **Critical Bugs**: Logic errors, null pointer risks, race conditions -3. **Breaking Changes**: API changes without versioning, removed functionality -4. **Code Quality**: Missing error handling, code smells, anti-patterns -5. **Performance**: Inefficient algorithms, memory leaks, N+1 queries +Analyze the following changes and identify SPECIFIC risks in these categories: +1. **Security Risks**: Exposed credentials, insecure patterns, authentication/authorization issues +2. **Breaking Changes**: API changes, database schema changes, removed functionality +3. **Performance Concerns**: Inefficient algorithms, memory leaks, N+1 queries +4. **Code Quality**: Complex logic, missing error handling, lack of tests +5. **Operational Risks**: Configuration changes, deployment concerns, dependency updates PR Title: ${context.title || 'No title provided'} Files changed: ${fileList} -Diff: +Diff sample: \`\`\` ${diffSample} \`\`\` -${securityContext ? `IMPORTANT: Reference repository documentation when applicable.` : ''} +${securityContext ? `CRITICAL INSTRUCTIONS: +- You MUST reference the repository documentation guidelines above when identifying each risk +- For EVERY risk you identify, find the relevant guideline from the documentation +- Explain HOW the code change violates or conflicts with the documented standards +- Quote the specific guideline that makes this a risk +- Be specific about why this matters based on the repository's own standards -For EACH issue found, provide: -- **file**: The file path where the issue exists -- **line**: Approximate line number (if you can identify it from the diff, otherwise omit) -- **comment**: Actionable PR comment explaining the issue and how to fix it. Be specific and helpful. -- **severity**: "critical" (must fix), "warning" (should fix), or "suggestion" (nice to have) +Example format for a risk with documentation: +{ + "description": "File exceeds maximum line count recommended for maintainability", + "archDocsSource": "code-quality.md", + "archDocsExcerpt": "Keep individual files under 500 lines to maintain testability and readability", + "reason": "This file contains 990 lines, nearly 2x the repository standard, which increases maintenance burden and makes comprehensive testing more difficult" +} +` : ''} -Return a JSON array of fix objects: -[ - { - "file": "src/path/to/file.ts", - "line": 42, - "comment": "**Security Issue**: Hardcoded API key detected. Use environment variables instead.\n\n**Fix**: Move to process.env.API_KEY or use a secrets manager.", - "severity": "critical" - }, +Provide a JSON array of risk objects. Each risk MUST include: +- description: Clear, specific description of the risk +${securityContext ? `- archDocsSource: REQUIRED - Which documentation file from above this relates to (e.g., "security.md", "patterns.md", "code-quality.md") +- archDocsExcerpt: REQUIRED - Direct quote from the repository documentation that this violates +- reason: REQUIRED - Detailed explanation of why this is a risk based on the specific guideline quoted above +` : ''} + +Format: +${securityContext ? `[ { - "file": "src/utils/helper.ts", - "comment": "**Missing Error Handling**: This function can throw but errors aren't caught.\n\n**Fix**: Wrap in try-catch or add error handling.", - "severity": "warning" + "description": "Specific risk description", + "archDocsSource": "documentation-file.md", + "archDocsExcerpt": "Exact quote from the documentation", + "reason": "Detailed explanation connecting the code change to the guideline violation" } ] -Only include CRUCIAL fixes that matter. If no significant issues, return an empty array [].`; +DO NOT return simple string arrays. Each risk MUST be an object with archDocsSource, archDocsExcerpt, and reason fields.` : '["risk 1", "risk 2", ...]'} + +Only include risks that are actually present. If no significant risks, return an empty array [].`; try { - const response = await this.model.invoke(fixesPrompt); + if (!this.model) { + throw new Error('LLM is required for risk detection in EXECUTE mode'); + } + const response = await this.model.invoke(riskPrompt); const content = response.content; // Track tokens const usage = response.response_metadata?.usage; const inputTokens = usage?.input_tokens || 0; const outputTokens = usage?.output_tokens || 0; // Parse JSON response - let fixes = []; + let risks = []; + let hasArchDocsEnhancement = false; try { // Extract JSON from markdown code blocks if present const jsonMatch = content.match(/\[[\s\S]*\]/); if (jsonMatch) { - const parsedFixes = JSON.parse(jsonMatch[0]); - fixes = parsedFixes - .filter((f) => f.file && f.comment) - .map((f) => ({ - file: f.file, - line: f.line, - comment: f.comment, - severity: f.severity || 'warning', - source: 'ai', - })) - // Prioritize critical and warning fixes, limit suggestions - .sort((a, b) => { - const severityOrder = { critical: 0, warning: 1, suggestion: 2 }; - const aSeverity = a.severity || 'warning'; - const bSeverity = b.severity || 'warning'; - return (severityOrder[aSeverity] ?? 2) - (severityOrder[bSeverity] ?? 2); - }) - // Limit to top 10 fixes (prioritize critical/warning) - .slice(0, 10); + const parsedRisks = JSON.parse(jsonMatch[0]); + // Check if risks have arch-docs references + if (parsedRisks.length > 0 && typeof parsedRisks[0] === 'object' && 'archDocsSource' in parsedRisks[0]) { + // Transform to our RiskItem format + risks = parsedRisks.map((r) => ({ + description: r.description, + archDocsReference: r.archDocsSource ? { + source: r.archDocsSource, + excerpt: r.archDocsExcerpt || '', + reason: r.reason || '', + } : undefined, + })); + hasArchDocsEnhancement = true; + } + else if (parsedRisks.length > 0 && typeof parsedRisks[0] === 'string') { + // Legacy format - just strings + risks = parsedRisks; + } + else { + risks = parsedRisks; + } } } catch (parseError) { - console.warn('Failed to parse fixes JSON:', parseError); + console.warn('Failed to parse risk JSON, extracting manually'); + // Fallback: extract bullet points as strings + const lines = content.split('\n'); + risks = lines + .filter(line => line.trim().startsWith('-') || line.trim().startsWith('•')) + .map(line => line.replace(/^[-•]\s*/, '').trim()) + .filter(line => line.length > 0); } - // Add pattern-based fixes for critical issues + // Add basic pattern-based checks with arch-docs enhancement + const patternRisks = []; if (context.diff.includes('password') || context.diff.includes('secret') || context.diff.includes('api_key')) { - const fileMatch = context.diff.match(/^diff --git a\/.*? b\/(.+)$/m); - const affectedFile = fileMatch ? fileMatch[1] : 'unknown'; - fixes.push({ - file: affectedFile, - comment: '**Security Issue**: Potential hardcoded credentials detected. Use environment variables or a secrets manager instead of hardcoding sensitive values.', - severity: 'critical', - source: 'ai', - }); - } - // Track arch-docs usage - const archDocsStages = securityContext ? ['fix-generation'] : []; + const riskDesc = 'Potential credentials or sensitive data in code changes'; + if (securityDoc) { + // Always enhance with arch-docs if available + patternRisks.push({ + description: riskDesc, + archDocsReference: { + source: 'security.md', + excerpt: 'Never commit credentials, API keys, or secrets to the repository. Use environment variables for all sensitive configuration.', + reason: 'Code changes contain keywords like "password", "secret", or "api_key" which may indicate hardcoded credentials. This violates the repository security policy requiring all secrets to be externalized via environment variables.', + }, + }); + } + else { + patternRisks.push(riskDesc); + } + } + if (fileAnalyses.size > 20) { + const qualityDoc = allDocs.find(d => d.filename === 'code-quality'); + if (qualityDoc && securityContext) { + patternRisks.push({ + description: `Large change set (${fileAnalyses.size} files) increases review complexity and error risk`, + archDocsReference: { + source: 'code-quality.md', + excerpt: 'Keep pull requests focused and under 15 files when possible for thorough review', + reason: `This PR modifies ${fileAnalyses.size} files, exceeding the recommended limit. Large PRs are harder to review thoroughly and increase the likelihood of missing critical issues.`, + }, + }); + } + else { + patternRisks.push(`Large change set (${fileAnalyses.size} files) - may be difficult to review thoroughly`); + } + } + if (context.diff.includes('DROP TABLE') || context.diff.includes('ALTER TABLE')) { + if (securityContext) { + patternRisks.push({ + description: 'Database schema changes detected - requires careful migration planning', + archDocsReference: { + source: 'patterns.md', + excerpt: 'All database schema changes must be backwards-compatible and include rollback procedures', + reason: 'The changes include database schema modifications (DROP TABLE or ALTER TABLE) which can cause data loss or application downtime if not properly planned and tested.', + }, + }); + } + else { + patternRisks.push('Database schema changes detected - requires careful migration planning'); + } + } + // Merge risks, avoiding duplicates (for string risks) + let allRisks; + if (hasArchDocsEnhancement) { + // Keep structured risks + allRisks = [...risks, ...patternRisks]; + } + else { + // Deduplicate string risks + allRisks = [...new Set([...risks, ...patternRisks])]; + } + // Track arch-docs usage in risk detection + const archDocsStages = securityContext ? ['risk-detection'] : []; const archDocsInsights = []; - if (securityContext && context.archDocs?.available && fixes.length > 0) { - archDocsInsights.push(`Generated ${fixes.length} fixes based on repository guidelines`); + if (securityContext && context.archDocs?.available) { + const enhancedCount = allRisks.filter(r => typeof r === 'object' && r.archDocsReference).length; + if (enhancedCount > 0) { + archDocsInsights.push(`Linked ${enhancedCount} risks to specific repository security guidelines and best practices`); + } } return { ...state, - fixes, - insights: [`Generated ${fixes.length} crucial fixes`], + currentRisks: allRisks, + insights: [`Identified ${allRisks.length} potential risks`], totalInputTokens: (state.totalInputTokens || 0) + inputTokens, totalOutputTokens: (state.totalOutputTokens || 0) + outputTokens, archDocsInfluencedStages: archDocsStages, @@ -639,16 +997,49 @@ Only include CRUCIAL fixes that matter. If no significant issues, return an empt }; } catch (error) { - console.error('Error generating fixes:', error); + console.error('Error in risk detection:', error); + // Fallback to basic pattern matching + const basicRisks = []; + if (context.diff.includes('password') || context.diff.includes('secret')) { + basicRisks.push('Potential credentials in diff'); + } + if (fileAnalyses.size > 15) { + basicRisks.push('Large change set - difficult to review'); + } return { ...state, - fixes: [], - insights: ['Fix generation encountered an error'], + currentRisks: basicRisks, + insights: [`Identified ${basicRisks.length} potential risks (basic analysis)`], }; } } + async calculateComplexityNode(state) { + const { fileAnalyses, context } = state; + console.log('📊 Calculating complexity...'); + const complexities = Array.from(fileAnalyses.values()).map(f => f.complexity); + const avgComplexity = complexities.length > 0 + ? complexities.reduce((a, b) => a + b, 0) / complexities.length + : 1; + // Track arch-docs influence on complexity + const archDocsStages = context.archDocs?.available ? ['complexity-calculation'] : []; + const archDocsInsights = []; + if (context.archDocs?.available) { + // Check if patterns documentation helped understand complexity + const allDocs = parseAllArchDocs(); + const patterns = getPatternsContext(allDocs); + if (patterns) { + archDocsInsights.push(`Evaluated complexity against repository design patterns and coding standards`); + } + } + return { + ...state, + currentComplexity: Math.round(avgComplexity), + archDocsInfluencedStages: archDocsStages, + archDocsKeyInsights: archDocsInsights, + }; + } async generateSummaryNode(state) { - const { context, fileAnalyses, fixes, semgrepSummary } = state; + const { context, fileAnalyses, currentRisks, currentComplexity } = state; console.log('📝 Generating detailed summary...'); const totalFiles = fileAnalyses.size; const totalAdditions = Array.from(fileAnalyses.values()).reduce((sum, f) => sum + f.changes.additions, 0); @@ -656,7 +1047,7 @@ Only include CRUCIAL fixes that matter. If no significant issues, return an empt // Build file list with changes const fileList = Array.from(fileAnalyses.entries()) .slice(0, 20) - .map(([path, analysis]) => `- ${path}: +${analysis.changes.additions} -${analysis.changes.deletions}`) + .map(([path, analysis]) => `- ${path}: +${analysis.changes.additions} -${analysis.changes.deletions} (complexity: ${analysis.complexity}/5)`) .join('\n'); // Add patterns context from arch-docs if available let patternsContext = ''; @@ -667,36 +1058,37 @@ Only include CRUCIAL fixes that matter. If no significant issues, return an empt patternsContext = `\n## Design Patterns from Repository Documentation\n\n${patterns.substring(0, 2000)}\n`; } } - // Add Semgrep summary if available - let semgrepSummaryContext = ''; - if (semgrepSummary && semgrepSummary.totalFindings > 0) { - semgrepSummaryContext = `\n## Static Analysis Summary (Semgrep)\n\n`; - semgrepSummaryContext += `- Total findings: ${semgrepSummary.totalFindings}\n`; - semgrepSummaryContext += `- Errors: ${semgrepSummary.errorCount}\n`; - semgrepSummaryContext += `- Warnings: ${semgrepSummary.warningCount}\n`; - semgrepSummaryContext += `- Categories affected: ${semgrepSummary.categoriesAffected.join(', ')}\n`; - semgrepSummaryContext += `- Files with issues: ${semgrepSummary.filesWithIssues.length}\n\n`; - } - // Create concise prompt for quick reading - const summaryPrompt = `Analyze this pull request and provide a BRIEF, scannable summary (2-3 sentences max). + // Create comprehensive prompt for LLM + const summaryPrompt = `You are analyzing a pull request. Provide a DETAILED and COMPREHENSIVE summary that covers: -Focus on: -- **What**: What does this PR do? (one sentence) -- **Why**: What problem does it solve or what feature does it add? (one sentence) -- **Impact**: What parts of the codebase are affected? (one sentence if significant) +1. **Overall Purpose**: What is this PR trying to accomplish? What problem does it solve? +2. **Key Changes**: What are the main changes being made? Group related changes together. +3. **Impact Analysis**: What parts of the system are affected? What are the implications? +4. **Technical Details**: Mention important technical aspects (new dependencies, API changes, data model changes, etc.) +5. **Patterns Observed**: Any design patterns, refactoring, or architectural changes? +${patternsContext} PR Title: ${context.title || 'No title provided'} -${context.language ? `Language: ${context.language}${context.framework ? ` (${context.framework})` : ''}` : ''} -Stats: ${totalFiles} files, +${totalAdditions}/-${totalDeletions} lines${fixes.length > 0 ? `, ${fixes.filter((f) => f.severity === 'critical').length} critical fixes` : ''} +Statistics: +- Files changed: ${totalFiles} +- Lines added: ${totalAdditions} +- Lines deleted: ${totalDeletions} +- Overall complexity: ${currentComplexity}/5 +- Risks identified: ${currentRisks.length} -Key files: -${fileList.split('\n').slice(0, 5).join('\n')} +Files changed: +${fileList} + +${currentRisks.length > 0 ? `\nRisks detected:\n${currentRisks.map(r => `- ${r}`).join('\n')}` : ''} -${semgrepSummaryContext && semgrepSummary ? `Static analysis found ${semgrepSummary.totalFindings} issues (${semgrepSummary.errorCount} critical). ` : ''} +${patternsContext ? 'Consider the design patterns and architecture from the repository documentation when analyzing the changes.\n' : ''} -Write a concise summary that helps reviewers quickly understand the PR's purpose and scope. Be direct and specific.`; +Provide a detailed, well-structured summary (3-5 paragraphs) that would help a reviewer understand the scope and purpose of this PR.`; try { + if (!this.model) { + throw new Error('LLM is required for summary generation in EXECUTE mode'); + } const response = await this.model.invoke(summaryPrompt); const detailedSummary = response.content; // Track token usage @@ -709,9 +1101,6 @@ Write a concise summary that helps reviewers quickly understand the PR's purpose if (patternsContext && context.archDocs?.available) { archDocsInsights.push(`Generated summary aligned with repository architecture and established patterns`); } - if (semgrepSummary && semgrepSummary.totalFindings > 0) { - archDocsInsights.push(`Incorporated ${semgrepSummary.totalFindings} static analysis findings into summary`); - } return { ...state, currentSummary: detailedSummary, @@ -728,7 +1117,8 @@ Write a concise summary that helps reviewers quickly understand the PR's purpose - Files changed: ${totalFiles} - Additions: ${totalAdditions} - Deletions: ${totalDeletions} -- Fixes identified: ${fixes.length} +- Overall complexity: ${currentComplexity}/5 +- Risks identified: ${currentRisks.length} ${context.title ? `Title: ${context.title}` : ''}`; return { @@ -737,10 +1127,21 @@ ${context.title ? `Title: ${context.title}` : ''}`; }; } } - async finalizeNode(state) { - const { currentSummary, fixes, fileAnalyses, context } = state; - console.log('✨ Finalizing analysis and generating recommendations...'); - // Build arch-docs context for recommendations if available + async evaluateQualityNode(state) { + const { iteration } = state; + console.log(`🔍 Evaluating quality (iteration ${iteration + 1})...`); + // Simple quality check + const clarityScore = 85; // Placeholder + return { + ...state, + clarityScore, + iteration: iteration + 1, + }; + } + async refineAnalysisNode(state) { + const { currentSummary, currentRisks, fileAnalyses, context } = state; + console.log('🔄 Refining analysis...'); + // Build arch-docs context for refinement let archDocsRefinementContext = ''; if (context.archDocs?.available) { const allDocs = parseAllArchDocs(); @@ -754,24 +1155,41 @@ ${context.title ? `Title: ${context.title}` : ''}`; if (qualityDoc) { archDocsRefinementContext += `\n## Code Quality Standards\n\n${qualityDoc.content.substring(0, 2000)}\n`; } + // Get KPI metrics + const kpiDoc = allDocs.find(d => d.filename === 'kpi'); + if (kpiDoc) { + archDocsRefinementContext += `\n## Repository Health KPIs\n\n${kpiDoc.content.substring(0, 1500)}\n`; + } } - // Generate recommendations - const refinementPrompt = `Based on this PR analysis, provide 3-5 specific, actionable recommendations. - ${archDocsRefinementContext} - - PR Summary: - ${currentSummary} - - Fixes Identified: ${fixes.length} - ${fixes.length > 0 ? `\nKey fixes:\n${fixes.slice(0, 5).map(f => `- ${f.file}${f.line ? `:${f.line}` : ''}: ${f.comment.substring(0, 100)}...`).join('\n')}` : ''} - - Files Changed: ${fileAnalyses.size} - - ${archDocsRefinementContext ? 'Use the repository guidelines above to ensure recommendations align with established practices.\n' : ''} - - Provide a JSON array of recommendations: - ["recommendation 1", "recommendation 2", ...]`; + // Generate comprehensive recommendations + const refinementPrompt = `Based on this PR analysis, provide specific, actionable recommendations for the developer and reviewers. +${archDocsRefinementContext} + +PR Summary: +${currentSummary} + +Risks Identified: +${currentRisks.map(r => `- ${r}`).join('\n')} + +Files Changed: ${fileAnalyses.size} + +Consider: +1. Code organization and structure improvements +2. Testing recommendations +3. Documentation needs +4. Performance optimizations +5. Security enhancements +6. Review process suggestions +${archDocsRefinementContext ? '7. Alignment with repository standards and KPIs from arch-docs\n' : ''} + +${archDocsRefinementContext ? 'Use the repository guidelines and standards above to ensure recommendations align with established practices.\n' : ''} + +Provide a JSON array of 3-5 specific, actionable recommendations: +["recommendation 1", "recommendation 2", ...]`; try { + if (!this.model) { + throw new Error('LLM is required for self refinement in EXECUTE mode'); + } const response = await this.model.invoke(refinementPrompt); const content = response.content; // Track tokens @@ -803,23 +1221,23 @@ ${context.title ? `Title: ${context.title}` : ''}`; 'Consider performance implications of changes', ]; } - // Track arch-docs usage - const archDocsStages = archDocsRefinementContext ? ['finalization'] : []; + // Track arch-docs usage in refinement + const archDocsStages = archDocsRefinementContext ? ['refinement'] : []; const archDocsInsights = []; if (archDocsRefinementContext && context.archDocs?.available) { - archDocsInsights.push(`Generated ${recommendations.length} recommendations based on repository quality standards`); + archDocsInsights.push(`Generated ${recommendations.length} recommendations based on repository quality standards and KPIs`); } return { ...state, recommendations, totalInputTokens: (state.totalInputTokens || 0) + inputTokens, totalOutputTokens: (state.totalOutputTokens || 0) + outputTokens, - archDocsInfluencedStages: [...(state.archDocsInfluencedStages || []), ...archDocsStages], - archDocsKeyInsights: [...(state.archDocsKeyInsights || []), ...archDocsInsights], + archDocsInfluencedStages: archDocsStages, + archDocsKeyInsights: archDocsInsights, }; } catch (error) { - console.error('Error generating recommendations:', error); + console.error('Error refining analysis:', error); return { ...state, recommendations: [ @@ -830,5 +1248,24 @@ ${context.title ? `Title: ${context.title}` : ''}`; }; } } + async finalizeNode(state) { + console.log('✨ Finalizing analysis...'); + return state; + } + shouldRefine(state) { + // Use defaults if config not accessible + const maxIterations = 3; + const clarityThreshold = 80; + if (state.iteration >= maxIterations) { + console.log(`⏹️ Stopping: Max iterations (${maxIterations}) reached`); + return 'finalize'; + } + if (state.clarityScore >= clarityThreshold) { + console.log(`✅ Stopping: Clarity threshold (${clarityThreshold}) achieved`); + return 'finalize'; + } + console.log(`🔄 Continuing: Iteration ${state.iteration}, clarity ${state.clarityScore}`); + return 'refine'; + } } //# sourceMappingURL=base-pr-agent-workflow.js.map \ No newline at end of file diff --git a/dist/agents/base-pr-agent-workflow.js.map b/dist/agents/base-pr-agent-workflow.js.map index 25d9de2..9e9b000 100644 --- a/dist/agents/base-pr-agent-workflow.js.map +++ b/dist/agents/base-pr-agent-workflow.js.map @@ -1 +1 @@ -{"version":3,"file":"base-pr-agent-workflow.js","sourceRoot":"","sources":["../../src/agents/base-pr-agent-workflow.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"base-pr-agent-workflow.js","sourceRoot":"","sources":["../../src/agents/base-pr-agent-workflow.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EASL,aAAa,GAId,MAAM,yBAAyB,CAAC;AACjC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC5G,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EACL,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GAEnB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,YAAY,EACZ,kBAAkB,GACnB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,eAAe,EACf,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE1D;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC;IAC1C,gBAAgB;IAChB,OAAO,EAAE,UAAU,CAAe;QAChC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM;KAC/B,CAAC;IAEF,oBAAoB;IACpB,SAAS,EAAE,UAAU,CAAS;QAC5B,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM;QAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;KACjB,CAAC;IAEF,gBAAgB;IAChB,YAAY,EAAE,UAAU,CAA4B;QAClD,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM;QAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE;KACzB,CAAC;IAEF,yBAAyB;IACzB,cAAc,EAAE,UAAU,CAAS;QACjC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM;QAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;IAEF,YAAY,EAAE,UAAU,CAAQ;QAC9B,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM;QAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;IAEF,iBAAiB,EAAE,UAAU,CAAS;QACpC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM;QAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;KACjB,CAAC;IAEF,kBAAkB;IAClB,YAAY,EAAE,UAAU,CAAS;QAC/B,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM;QAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;KACjB,CAAC;IAEF,kBAAkB,EAAE,UAAU,CAAW;QACvC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM;QAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;IAEF,kBAAkB;IAClB,eAAe,EAAE,UAAU,CAAW;QACpC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM;QAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;IAEF,yBAAyB;IACzB,QAAQ,EAAE,UAAU,CAAW;QAC7B,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC;QACrD,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;IAEF,SAAS,EAAE,UAAU,CAAW;QAC9B,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC;QACrD,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;IAEF,qBAAqB;IACrB,wBAAwB,EAAE,UAAU,CAAW;QAC7C,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC;QACrD,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;IAEF,mBAAmB,EAAE,UAAU,CAAW;QACxC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC;QACrD,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;KAClB,CAAC;IAEF,iBAAiB;IACjB,gBAAgB,EAAE,UAAU,CAAS;QACnC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,GAAG,MAAM;QAC9C,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;KACjB,CAAC;IAEF,iBAAiB,EAAE,UAAU,CAAS;QACpC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,GAAG,MAAM;QAC9C,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;KACjB,CAAC;CACH,CAAC,CAAC;AAWH;;GAEG;AACH,MAAM,OAAgB,mBAAmB;IAC7B,KAAK,CAAiB,CAAE,gBAAgB;IACxC,IAAI,CAAgB;IACpB,QAAQ,CAAyC,CAAE,+BAA+B;IAClF,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC;IACjC,KAAK,CAAQ;IAEvB,YAAY,OAAsB,aAAa,CAAC,OAAO,EAAE,KAAqB;QAC5E,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QAEnB,2CAA2C;QAC3C,IAAI,IAAI,KAAK,aAAa,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;QAED,mBAAmB;QACnB,IAAI,CAAC,KAAK,GAAG;YACX,sBAAsB,EAAE;YACxB,sBAAsB,EAAE;YACxB,0BAA0B,EAAE;YAC5B,0BAA0B,EAAE;SAC7B,CAAC;QAEF,sCAAsC;QACtC,IAAI,IAAI,KAAK,aAAa,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACvC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,aAAa;QACnB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;QAE3C,eAAe;QACf,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAChE,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9D,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9E,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACtE,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACtE,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAExD,kBAAkB;QAClB,MAAM,UAAU,GAAG,cAA6B,CAAC;QACjD,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QAEhC,uBAAuB;QACvB,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,aAA4B,CAAC,CAAC;QACxD,KAAK,CAAC,OAAO,CAAC,aAA4B,EAAE,qBAAoC,CAAC,CAAC;QAClF,KAAK,CAAC,OAAO,CAAC,qBAAoC,EAAE,iBAAgC,CAAC,CAAC;QACtF,KAAK,CAAC,OAAO,CAAC,iBAAgC,EAAE,iBAAgC,CAAC,CAAC;QAElF,kCAAkC;QAClC,KAAK,CAAC,mBAAmB,CAAC,iBAAgC,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACxF,MAAM,EAAE,gBAA+B;YACvC,QAAQ,EAAE,UAAyB;SACpC,CAAC,CAAC;QAEH,mCAAmC;QACnC,KAAK,CAAC,OAAO,CAAC,gBAA+B,EAAE,iBAAgC,CAAC,CAAC;QAEjF,yBAAyB;QACzB,KAAK,CAAC,OAAO,CAAC,UAAyB,EAAE,GAAG,CAAC,CAAC;QAE9C,OAAO,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,OAAqB,EAAE,OAA+B;QAClE,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,CAAC,WAAW,EAAE,CAAC;YAC5C,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,eAAe,CAAC,OAAqB;QACjD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,OAAO,GAAqB,EAAE,CAAC;QAErC,uCAAuC;QACvC,IAAI,eAAe,GAAG,EAAE,CAAC;QACzB,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;YAChC,eAAe,GAAG,uBAAuB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC9D,CAAC;QAED,8CAA8C;QAC9C,wEAAwE;QACxE,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;QACnD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,2BAA2B,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9E,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAE1C,iDAAiD;QACjD,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAC/C,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,GAAG,EAAE;YAC9B,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACzB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACzB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC5B,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CACxB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAEd,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;QAC9E,CAAC;QAED,2BAA2B;QAC3B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;QAE7E,+BAA+B;QAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;QAEvE,wEAAwE;QACxE,8DAA8D;QAC9D,oEAAoE;QAEpE,OAAO;YACL,IAAI,EAAE,aAAa;YACnB,OAAO;YACP,OAAO;YACP,kCAAkC;YAClC,cAAc;YACd,YAAY,EAAE;;;;;;;;qHAQiG;SAChH,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,uBAAuB,CAAC,cAA0B,EAAE,eAAuB;QACjF,MAAM,MAAM,GAAG;EACjB,eAAe,CAAC,CAAC,CAAC,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE;;;EAG7C,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAClB,CAAC,CAAC,IAAI;UACJ,CAAC,CAAC,MAAM,IAAI,UAAU;YACpB,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS;;;EAGrC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;;CAEzB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;;EAEhB,eAAe,CAAC,CAAC,CAAC;;;;;;;CAOnB,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;EAYJ,eAAe,CAAC,CAAC,CAAC,gGAAgG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAExH,OAAO;YACL,IAAI,EAAE,cAAc;YACpB,MAAM;YACN,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,CAAC,MAAM,EAAE;YAC7C,YAAY,EAAE,6DAA6D;SAC5E,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,wBAAwB,CAAC,KAAiB,EAAE,eAAuB,EAAE,OAAqB;QAChG,MAAM,MAAM,GAAG;;EAEjB,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;;iBAEvB,KAAK,CAAC,MAAM;EAC3B,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;EAI1E,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC;;;EAG/B,eAAe,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;yHAeqG,CAAC,CAAC,CAAC,2BAA2B;;iGAEtD,CAAC;QAE9F,OAAO;YACL,IAAI,EAAE,eAAe;YACrB,MAAM;YACN,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE;YACpC,YAAY,EAAE,oDAAoD;SACnE,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,kBAAkB,CAAC,KAAiB,EAAE,eAAuB,EAAE,OAAqB;QAC1F,MAAM,MAAM,GAAG;;EAEjB,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;;YAE5B,OAAO,CAAC,KAAK,IAAI,aAAa;;iBAEzB,KAAK,CAAC,MAAM;oBACT,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;oBAC9C,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;;;EAGhE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;EAIvF,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC;;;EAG/B,eAAe,CAAC,CAAC,CAAC,+GAA+G,CAAC,CAAC,CAAC,EAAE;;qIAEH,CAAC;QAElI,OAAO;YACL,IAAI,EAAE,mBAAmB;YACzB,MAAM;YACN,OAAO,EAAE,EAAE;YACX,YAAY,EAAE,+CAA+C;SAC9D,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,eAAe,CAAC,OAAqB,EAAE,OAA+B;QAClF,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,kFAAkF,CAAC,CAAC;QACtG,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,kCAAkC;QAClC,IAAI,OAAO,EAAE,kBAAkB,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,MAAM,GAA0B;YACpC,aAAa,EAAE,CAAC;YAChB,gBAAgB,EAAE,EAAE;YACpB,kBAAkB,EAAE,KAAK;SAC1B,CAAC;QAEF,MAAM,YAAY,GAAG;YACnB,OAAO;YACP,SAAS,EAAE,CAAC;YACZ,YAAY,EAAE,IAAI,GAAG,EAAE;YACvB,cAAc,EAAE,EAAE;YAClB,YAAY,EAAE,EAAE;YAChB,iBAAiB,EAAE,CAAC;YACpB,YAAY,EAAE,CAAC;YACf,kBAAkB,EAAE,EAAE;YACtB,eAAe,EAAE,EAAE;YACnB,QAAQ,EAAE,EAAE;YACZ,SAAS,EAAE,EAAE;YACb,gBAAgB,EAAE,CAAC;YACnB,iBAAiB,EAAE,CAAC;SACrB,CAAC;QAEF,MAAM,cAAc,GAAG;YACrB,YAAY,EAAE;gBACZ,SAAS,EAAE,YAAY,IAAI,CAAC,GAAG,EAAE,EAAE;gBACnC,aAAa,EAAE,MAAM,CAAC,aAAa;gBACnC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;aAC1C;YACD,cAAc,EAAE,EAAE;SACnB,CAAC;QAEF,IAAI,UAAU,GAAG,YAAY,CAAC;QAC9B,IAAI,gBAAgB,GAAG,CAAC,CAAC;QACzB,IAAI,iBAAiB,GAAG,CAAC,CAAC;QAE1B,kDAAkD;QAClD,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,cAAqB,CAAC,EAAE,CAAC;gBAC1F,4BAA4B;gBAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzB,MAAM,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACrD,UAAU,GAAI,KAAa,CAAC,YAAY,CAAC,IAAI,UAAU,CAAC;oBAExD,kCAAkC;oBAClC,MAAM,QAAQ,GAAG,UAAiB,CAAC;oBACnC,IAAI,QAAQ,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;wBAC5C,gBAAgB,GAAG,QAAQ,CAAC,gBAAgB,CAAC;oBAC/C,CAAC;oBACD,IAAI,QAAQ,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;wBAC7C,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAC;oBACjD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;YAClD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAE7C,oDAAoD;QACpD,MAAM,QAAQ,GAAG,UAAiB,CAAC;QACnC,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;YACnD,IAAI,EAAE,IAAI;YACV,aAAa,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS;YACzC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM;YAClD,gBAAgB,EAAE,CAAC,GAAG,IAAI,GAAG,CAAS,QAAQ,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;YAC/E,WAAW,EAAE,CAAC,GAAG,IAAI,GAAG,CAAS,QAAQ,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;SACtE,CAAC,CAAC,CAAC,SAAS,CAAC;QAEd,yDAAyD;QACzD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,2BAA2B,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAE9E,kEAAkE;QAClE,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE;YACtD,0CAA0C;YAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,OAAO;oBACL,IAAI,EAAE,EAAE;oBACR,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,SAAkB;iBAC7B,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;gBACrB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC;gBACxD,QAAQ,EAAG,IAAI,CAAC,QAAkD,IAAI,SAAS;aAChF,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,UAAU,CAAC,cAAc;YAClC,YAAY,EAAE,UAAU,CAAC,YAAY;YACrC,KAAK;YACL,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;YAC/C,YAAY,EAAE,UAAU,CAAC,YAAY;YACrC,eAAe,EAAE,UAAU,CAAC,eAAe;YAC3C,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,SAAS,EAAE,UAAU,CAAC,SAAS;YAC/B,QAAQ,EAAE,IAAI;YACd,KAAK,EAAG,IAAI,CAAC,KAAa,CAAC,SAAS,IAAI,SAAS;YACjD,eAAe,EAAE,gBAAgB,GAAG,iBAAiB;YACrD,aAAa;YACb,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,cAAc;YACd,2DAA2D;YAC3D,GAAG,cAAc;SAClB,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,eAAe,CAAC,OAAqB,EAAE,SAAiB;QACpE,mBAAmB;QACnB,MAAM,YAAY,GAAG;YACnB,OAAO;YACP,SAAS,EAAE,CAAC;YACZ,YAAY,EAAE,IAAI,GAAG,EAAwB;YAC7C,cAAc,EAAE,EAAE;YAClB,YAAY,EAAE,EAAc;YAC5B,iBAAiB,EAAE,CAAC;YACpB,YAAY,EAAE,CAAC;YACf,kBAAkB,EAAE,EAAc;YAClC,eAAe,EAAE,EAAc;YAC/B,QAAQ,EAAE,EAAc;YACxB,SAAS,EAAE,EAAc;YACzB,gBAAgB,EAAE,CAAC;YACnB,iBAAiB,EAAE,CAAC;SACrB,CAAC;QAEF,6DAA6D;QAC7D,IAAI,KAAK,GAAQ,YAAY,CAAC;QAE9B,IAAI,CAAC;YACH,mBAAmB;YACnB,KAAK,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;YAE3C,kBAAkB;YAClB,KAAK,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAE1C,0BAA0B;YAC1B,KAAK,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;YAElD,sBAAsB;YACtB,KAAK,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAE9C,wDAAwD;YACxD,KAAK,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAE7C,cAAc;YACd,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YAEvC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAE7C,oDAAoD;YACpD,MAAM,QAAQ,GAAG,KAAY,CAAC;YAC9B,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;gBACnD,IAAI,EAAE,IAAI;gBACV,aAAa,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS;gBACzC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM;gBAClD,gBAAgB,EAAE,CAAC,GAAG,IAAI,GAAG,CAAS,QAAQ,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;gBAC/E,WAAW,EAAE,CAAC,GAAG,IAAI,GAAG,CAAS,QAAQ,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;aACtE,CAAC,CAAC,CAAC,SAAS,CAAC;YAEd,yDAAyD;YACzD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,2BAA2B,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAE9E,kEAAkE;YAClE,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE;gBACjD,0CAA0C;gBAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7B,OAAO;wBACL,IAAI,EAAE,EAAE;wBACR,OAAO,EAAE,IAAI;wBACb,QAAQ,EAAE,SAAkB;qBAC7B,CAAC;gBACJ,CAAC;gBACD,OAAO;oBACL,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;oBACrB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,OAAO,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC;oBACxD,QAAQ,EAAG,IAAI,CAAC,QAAkD,IAAI,SAAS;iBAChF,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,KAAK,CAAC,cAAc;gBAC7B,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,KAAK;gBACL,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;gBAC1C,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,eAAe,EAAE,KAAK,CAAC,eAAe;gBACtC,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,SAAS,EAAE,CAAC,GAAG,KAAK,CAAC,SAAS,EAAE,yDAAyD,CAAC;gBAC1F,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAG,IAAI,CAAC,KAAa,CAAC,SAAS,IAAI,SAAS;gBACjD,eAAe,EAAE,KAAK,CAAC,gBAAgB,GAAG,KAAK,CAAC,iBAAiB;gBACjE,aAAa;gBACb,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,cAAc;gBACd,2DAA2D;gBAC3D,GAAG,cAAc;aAClB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;YACnD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,2BAA2B,CACvC,KAAkF,EAClF,OAAqB;QAOrB,MAAM,MAAM,GAKR,EAAE,CAAC;QAEP,iCAAiC;QACjC,6EAA6E;QAC7E,MAAM,SAAS,GAAI,OAAO,CAAC,MAAM,EAAE,SAAoB,IAAI,OAAO,CAAC;QACnE,MAAM,QAAQ,GAAI,OAAO,CAAC,MAAM,EAAE,QAAmB,IAAI,SAAS,CAAC;QAEnE,IAAI,oBAAoB,GAAG,wBAAwB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEzE,IAAI,oBAAoB,EAAE,CAAC;YACzB,4BAA4B;YAC5B,MAAM,CAAC,qBAAqB,GAAG,oBAAoB,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,2CAA2C;YAC3C,MAAM,cAAc,GAAG,eAAe,CACpC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CACtD,CAAC;YACF,MAAM,CAAC,qBAAqB,GAAG,oBAAoB,CAAC,cAAc,CAAC,CAAC;QACtE,CAAC;QAED,2BAA2B;QAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/E,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACxD,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;QAErE,OAAO,CAAC,GAAG,CAAC,uBAAuB,SAAS,CAAC,MAAM,gBAAgB,SAAS,CAAC,MAAM,gBAAgB,WAAW,CAAC,MAAM,eAAe,CAAC,CAAC;QAEtI,wDAAwD;QACxD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,qCAAqC,SAAS,CAAC,MAAM,gBAAgB,CAAC,CAAC;YAEnF,MAAM,aAAa,GAAG,mBAAmB,CAAC,OAAO,CAAC,MAAM,EAAE,QAAkB,IAAI,GAAG,CAAC,CAAC;YACrF,MAAM,eAAe,GAAqB,EAAE,CAAC;YAE7C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;gBAC7B,uDAAuD;gBACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;gBAC3E,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACjC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CACtD,CAAC;gBAEF,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;oBACnC,8DAA8D;oBAC9D,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,2CAA2C,CAAC,IAAI,EAAE,CAAC;oBAC3F,MAAM,aAAa,GAAG,eAAe;yBAClC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,qCAAqC,EAAE,EAAE,CAAC,CAAC;yBAC9D,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;oBAE5E,MAAM,QAAQ,GAAG,oBAAoB,CACnC,aAAa,CAAC,SAAS,EACvB,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,IAAI,EACT,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAC1B,CAAC;oBAEF,eAAe,CAAC,IAAI,CAAC;wBACnB,OAAO,EAAE,IAAI,CAAC,IAAI;wBAClB,aAAa,EAAE,aAAa,CAAC,SAAS;wBACtC,QAAQ;wBACR,WAAW,EAAE,4CAA4C,IAAI,CAAC,IAAI,EAAE;wBACpE,YAAY,EAAE,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC;qBACtE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,MAAM,CAAC,eAAe,GAAG,eAAe,CAAC;gBACzC,OAAO,CAAC,GAAG,CAAC,eAAe,eAAe,CAAC,MAAM,mBAAmB,CAAC,CAAC;YACxE,CAAC;QACH,CAAC;QAED,oDAAoD;QACpD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjD,OAAO,CAAC,GAAG,CAAC,gBAAgB,SAAS,CAAC,MAAM,4CAA4C,CAAC,CAAC;YAE1F,MAAM,aAAa,GAAG,mBAAmB,CAAC,OAAO,CAAC,MAAM,EAAE,QAAkB,IAAI,GAAG,CAAC,CAAC;YAErF,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,iCAAiC;gBACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI;qBAC3B,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC;qBAChC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC;qBACzC,OAAO,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;gBAE/C,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACpC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAC1E,CAAC;gBAEF,IAAI,UAAU,IAAI,QAAQ,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;oBACzC,gDAAgD;oBAChD,MAAM,WAAW,GAAG,kBAAkB,CACpC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,EAC5C,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,EAChD,aAAa,CAAC,SAAS,CACxB,CAAC;oBAEF,IAAI,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACvC,+CAA+C;wBAC/C,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC;wBACtD,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC;4BAC1B,OAAO,EAAE,UAAU,CAAC,IAAI;4BACxB,aAAa,EAAE,aAAa,CAAC,SAAS;4BACtC,QAAQ,EAAE,WAAW,CAAC,eAAe,IAAI,EAAE;4BAC3C,WAAW,EAAE,yBAAyB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;4BAC3G,YAAY,EAAE,QAAQ,CAAC,IAAI;4BAC3B,aAAa,EAAE,IAAI;4BACnB,gBAAgB,EAAE,QAAQ,CAAC,IAAI;yBAChC,CAAC,CAAC;wBAEH,OAAO,CAAC,GAAG,CAAC,cAAc,WAAW,CAAC,gBAAgB,CAAC,MAAM,2BAA2B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBAC1H,CAAC;gBACH,CAAC;YACH,CAAC;YAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;YAC1F,IAAI,gBAAgB,GAAG,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,eAAe,gBAAgB,iCAAiC,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,iCAAiC,WAAW,CAAC,MAAM,WAAW,CAAC,CAAC;YAE5E,MAAM,YAAY,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;YAErD,IAAI,YAAY,CAAC,gBAAgB,IAAI,YAAY,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvE,MAAM,CAAC,mBAAmB,GAAG,YAAY,CAAC,SAAS,CAAC;gBACpD,OAAO,CAAC,GAAG,CAAC,yBAAyB,YAAY,CAAC,SAAS,CAAC,MAAM,iBAAiB,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC1I,CAAC;QACH,CAAC;QAED,4DAA4D;QAC5D,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjD,MAAM,cAAc,GAAG,kBAAkB,CAAC,OAAO,CAAC,MAAM,EAAE,QAAkB,IAAI,GAAG,CAAC,CAAC;YAErF,IAAI,cAAc,CAAC,UAAU,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,yBAAyB,cAAc,CAAC,IAAI,eAAe,CAAC,CAAC;gBAEzE,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,MAAM,EAAE,QAAkB,IAAI,GAAG,CAAC,CAAC;gBAE/E,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;oBACvB,MAAM,CAAC,cAAc,GAAG,QAAQ,CAAC;oBACjC,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,iBAAiB;IAET,KAAK,CAAC,gBAAgB,CAAC,KAAgC;QAC7D,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;QAC1B,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEtC,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,CAAC,MAAM,WAAW,CAAC,CAAC;QAErD,qCAAqC;QACrC,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,wCAAwC,OAAO,CAAC,QAAQ,CAAC,SAAS,UAAU,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,qBAAqB,CAAC,CAAC;QACrJ,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,GAAG,EAAwB,CAAC;QAErD,uCAAuC;QACvC,IAAI,eAAe,GAAG,EAAE,CAAC;QACzB,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;YAChC,eAAe,GAAG,uBAAuB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC9D,CAAC;QAED,iDAAiD;QACjD,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,0CAA0C;QACrF,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAC/C,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,GAAG,EAAE,IAAI,sBAAsB;YACxD,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACzB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACzB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC5B,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CACxB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,wBAAwB;QAEvC,4CAA4C;QAC5C,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC;gBAEH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;oBAChB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;gBACvE,CAAC;gBAED,MAAM,iBAAiB,GAAG;EAChC,eAAe,CAAC,CAAC,CAAC,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE;;;EAG7C,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAClB,CAAC,CAAC,IAAI;UACJ,CAAC,CAAC,MAAM,IAAI,UAAU;YACpB,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS;;;EAGrC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;;CAEzB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;;EAEhB,eAAe,CAAC,CAAC,CAAC;;;;;;;CAOnB,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;EAYJ,eAAe,CAAC,CAAC,CAAC,gGAAgG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;gBAEpH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;gBAC5D,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAiB,CAAC;gBAE3C,eAAe;gBACf,MAAM,KAAK,GAAI,QAAQ,CAAC,iBAAyB,EAAE,KAAK,CAAC;gBACzD,MAAM,WAAW,GAAG,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC;gBAC7C,MAAM,YAAY,GAAG,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;gBAE/C,+BAA+B;gBAC/B,IAAI,CAAC;oBACH,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;oBAC/C,IAAI,SAAS,EAAE,CAAC;wBACd,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;wBAElD,2CAA2C;wBAC3C,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;4BAClC,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;4BAC3C,IAAI,MAAM,EAAE,CAAC;gCACX,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;oCAC1B,IAAI,EAAE,IAAI,CAAC,IAAI;oCACf,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,EAAE;oCACzF,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;oCACtD,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;oCACpG,OAAO,EAAE;wCACP,SAAS,EAAE,IAAI,CAAC,SAAS;wCACzB,SAAS,EAAE,IAAI,CAAC,SAAS;qCAC1B;oCACD,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;iCACrF,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,OAAO,UAAU,EAAE,CAAC;oBACpB,OAAO,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;gBAC3E,CAAC;gBAED,mCAAmC;gBACnC,KAAK,GAAG;oBACN,GAAG,KAAK;oBACR,gBAAgB,EAAE,CAAC,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC,GAAG,WAAW;oBAC7D,iBAAiB,EAAE,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,CAAC,GAAG,YAAY;iBACjE,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,yDAAyD,EAAE,KAAK,CAAC,CAAC;YACjF,CAAC;QACH,CAAC;QAED,yCAAyC;QACzC,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;YAClC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,MAAM,QAAQ,GAAiB;oBAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,EAAE;oBACvE,KAAK,EAAE,EAAE;oBACT,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;oBAC/E,OAAO,EAAE;wBACP,SAAS,EAAE,IAAI,CAAC,SAAS;wBACzB,SAAS,EAAE,IAAI,CAAC,SAAS;qBAC1B;oBACD,eAAe,EAAE,EAAE;iBACpB,CAAC;gBAEF,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,MAAM,WAAW,GAAG,CAAC,YAAY,KAAK,CAAC,MAAM,WAAW,cAAc,CAAC,MAAM,aAAa,CAAC,CAAC;QAC5F,MAAM,kBAAkB,GAAG,eAAe,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC;QACzE,MAAM,cAAc,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,MAAM,gBAAgB,GAAG,EAAE,CAAC;QAE5B,IAAI,kBAAkB,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;YACtD,gBAAgB,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,0FAA0F,CAAC,CAAC;QACnK,CAAC;QAED,OAAO;YACL,GAAG,KAAK;YACR,YAAY;YACZ,QAAQ,EAAE,WAAW;YACrB,wBAAwB,EAAE,cAAc;YACxC,mBAAmB,EAAE,gBAAgB;SACtC,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,KAAgC;QAC5D,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC;QAExC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QAEtC,kCAAkC;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;aAChD,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;aACZ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CACxB,GAAG,IAAI,MAAM,QAAQ,CAAC,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,OAAO,CAAC,SAAS,GAAG,CAC1E;aACA,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,0DAA0D;QAC1D,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,wBAAwB;QAE5E,mDAAmD;QACnD,IAAI,eAAe,GAAG,EAAE,CAAC;QACzB,IAAI,OAAO,GAAU,EAAE,CAAC;QACxB,IAAI,WAAW,GAAQ,IAAI,CAAC;QAC5B,IAAI,WAAW,GAAQ,IAAI,CAAC;QAE5B,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;YAChC,OAAO,GAAG,gBAAgB,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAC3C,IAAI,MAAM,EAAE,CAAC;gBACX,eAAe,GAAG,6DAA6D,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;gBAC7G,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;YAC7D,CAAC;YAED,8CAA8C;YAC9C,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAC7C,IAAI,QAAQ,EAAE,CAAC;gBACb,eAAe,IAAI,kDAAkD,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;gBACrG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG;EACrB,eAAe;;;;;;;;;YASL,OAAO,CAAC,KAAK,IAAI,mBAAmB;;;EAG9C,QAAQ;;;;EAIR,UAAU;;;EAGV,eAAe,CAAC,CAAC,CAAC;;;;;;;;;;;;;;CAcnB,CAAC,CAAC,CAAC,EAAE;;;;EAIJ,eAAe,CAAC,CAAC,CAAC;;;CAGnB,CAAC,CAAC,CAAC,EAAE;;;EAGJ,eAAe,CAAC,CAAC,CAAC;;;;;;;;;yHASqG,CAAC,CAAC,CAAC,2BAA2B;;iGAEtD,CAAC;QAE9F,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;YACxE,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACrD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAiB,CAAC;YAE3C,eAAe;YACf,MAAM,KAAK,GAAI,QAAQ,CAAC,iBAAyB,EAAE,KAAK,CAAC;YACzD,MAAM,WAAW,GAAG,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC;YAC7C,MAAM,YAAY,GAAG,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;YAE/C,sBAAsB;YACtB,IAAI,KAAK,GAAU,EAAE,CAAC;YACtB,IAAI,sBAAsB,GAAG,KAAK,CAAC;YAEnC,IAAI,CAAC;gBACH,oDAAoD;gBACpD,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;gBAC/C,IAAI,SAAS,EAAE,CAAC;oBACd,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;oBAE7C,2CAA2C;oBAC3C,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,WAAW,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,gBAAgB,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;wBACvG,mCAAmC;wBACnC,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;4BACnC,WAAW,EAAE,CAAC,CAAC,WAAW;4BAC1B,iBAAiB,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;gCACpC,MAAM,EAAE,CAAC,CAAC,cAAc;gCACxB,OAAO,EAAE,CAAC,CAAC,eAAe,IAAI,EAAE;gCAChC,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;6BACvB,CAAC,CAAC,CAAC,SAAS;yBACd,CAAC,CAAC,CAAC;wBACJ,sBAAsB,GAAG,IAAI,CAAC;oBAChC,CAAC;yBAAM,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,WAAW,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;wBACxE,+BAA+B;wBAC/B,KAAK,GAAG,WAAW,CAAC;oBACtB,CAAC;yBAAM,CAAC;wBACN,KAAK,GAAG,WAAW,CAAC;oBACtB,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,UAAU,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;gBAC/D,6CAA6C;gBAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClC,KAAK,GAAG,KAAK;qBACV,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;qBAC1E,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;qBAChD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACrC,CAAC;YAED,4DAA4D;YAC5D,MAAM,YAAY,GAAU,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC7G,MAAM,QAAQ,GAAG,yDAAyD,CAAC;gBAC3E,IAAI,WAAW,EAAE,CAAC;oBAChB,6CAA6C;oBAC7C,YAAY,CAAC,IAAI,CAAC;wBAChB,WAAW,EAAE,QAAQ;wBACrB,iBAAiB,EAAE;4BACjB,MAAM,EAAE,aAAa;4BACrB,OAAO,EAAE,8HAA8H;4BACvI,MAAM,EAAE,kOAAkO;yBAC3O;qBACF,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;YAED,IAAI,YAAY,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;gBAC3B,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,cAAc,CAAC,CAAC;gBACpE,IAAI,UAAU,IAAI,eAAe,EAAE,CAAC;oBAClC,YAAY,CAAC,IAAI,CAAC;wBAChB,WAAW,EAAE,qBAAqB,YAAY,CAAC,IAAI,oDAAoD;wBACvG,iBAAiB,EAAE;4BACjB,MAAM,EAAE,iBAAiB;4BACzB,OAAO,EAAE,iFAAiF;4BAC1F,MAAM,EAAE,oBAAoB,YAAY,CAAC,IAAI,4IAA4I;yBAC1L;qBACF,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,YAAY,CAAC,IAAI,CAAC,qBAAqB,YAAY,CAAC,IAAI,iDAAiD,CAAC,CAAC;gBAC7G,CAAC;YACH,CAAC;YAED,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBAChF,IAAI,eAAe,EAAE,CAAC;oBACpB,YAAY,CAAC,IAAI,CAAC;wBAChB,WAAW,EAAE,wEAAwE;wBACrF,iBAAiB,EAAE;4BACjB,MAAM,EAAE,aAAa;4BACrB,OAAO,EAAE,0FAA0F;4BACnG,MAAM,EAAE,qKAAqK;yBAC9K;qBACF,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,YAAY,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;gBAC9F,CAAC;YACH,CAAC;YAED,sDAAsD;YACtD,IAAI,QAAe,CAAC;YACpB,IAAI,sBAAsB,EAAE,CAAC;gBAC3B,wBAAwB;gBACxB,QAAQ,GAAG,CAAC,GAAG,KAAK,EAAE,GAAG,YAAY,CAAC,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,2BAA2B;gBAC3B,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YACvD,CAAC;YAED,0CAA0C;YAC1C,MAAM,cAAc,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,MAAM,gBAAgB,GAAG,EAAE,CAAC;YAE5B,IAAI,eAAe,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;gBACnD,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC;gBAChG,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;oBACtB,gBAAgB,CAAC,IAAI,CAAC,UAAU,aAAa,sEAAsE,CAAC,CAAC;gBACvH,CAAC;YACH,CAAC;YAED,OAAO;gBACL,GAAG,KAAK;gBACR,YAAY,EAAE,QAAQ;gBACtB,QAAQ,EAAE,CAAC,cAAc,QAAQ,CAAC,MAAM,kBAAkB,CAAC;gBAC3D,gBAAgB,EAAE,CAAC,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC,GAAG,WAAW;gBAC7D,iBAAiB,EAAE,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,CAAC,GAAG,YAAY;gBAChE,wBAAwB,EAAE,cAAc;gBACxC,mBAAmB,EAAE,gBAAgB;aACtC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YAEjD,qCAAqC;YACrC,MAAM,UAAU,GAAa,EAAE,CAAC;YAChC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACzE,UAAU,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;YACD,IAAI,YAAY,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;gBAC3B,UAAU,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;YAC5D,CAAC;YAED,OAAO;gBACL,GAAG,KAAK;gBACR,YAAY,EAAE,UAAU;gBACxB,QAAQ,EAAE,CAAC,cAAc,UAAU,CAAC,MAAM,mCAAmC,CAAC;aAC/E,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,uBAAuB,CAAC,KAAgC;QACpE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;QAExC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAE5C,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAC9E,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC;YAC3C,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,YAAY,CAAC,MAAM;YAC/D,CAAC,CAAC,CAAC,CAAC;QAEN,0CAA0C;QAC1C,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,MAAM,gBAAgB,GAAG,EAAE,CAAC;QAE5B,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;YAChC,+DAA+D;YAC/D,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAC7C,IAAI,QAAQ,EAAE,CAAC;gBACb,gBAAgB,CAAC,IAAI,CAAC,8EAA8E,CAAC,CAAC;YACxG,CAAC;QACH,CAAC;QAED,OAAO;YACL,GAAG,KAAK;YACR,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;YAC5C,wBAAwB,EAAE,cAAc;YACxC,mBAAmB,EAAE,gBAAgB;SACtC,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAAC,KAAgC;QAChE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,GAAG,KAAK,CAAC;QAEzE,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QAEjD,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC;QACrC,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC1G,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAE1G,+BAA+B;QAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;aAChD,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;aACZ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CACxB,KAAK,IAAI,MAAM,QAAQ,CAAC,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,OAAO,CAAC,SAAS,iBAAiB,QAAQ,CAAC,UAAU,KAAK,CAClH;aACA,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,mDAAmD;QACnD,IAAI,eAAe,GAAG,EAAE,CAAC;QACzB,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAC7C,IAAI,QAAQ,EAAE,CAAC;gBACb,eAAe,GAAG,yDAAyD,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;YAC7G,CAAC;QACH,CAAC;QAED,sCAAsC;QACtC,MAAM,aAAa,GAAG;;;;;;;EAOxB,eAAe;;YAEL,OAAO,CAAC,KAAK,IAAI,mBAAmB;;;mBAG7B,UAAU;iBACZ,cAAc;mBACZ,cAAc;wBACT,iBAAiB;sBACnB,YAAY,CAAC,MAAM;;;EAGvC,QAAQ;;EAER,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,sBAAsB,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;;EAEjG,eAAe,CAAC,CAAC,CAAC,+GAA+G,CAAC,CAAC,CAAC,EAAE;;qIAEH,CAAC;QAElI,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;YAC5E,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YACxD,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAiB,CAAC;YAEnD,oBAAoB;YACpB,MAAM,KAAK,GAAI,QAAQ,CAAC,iBAAyB,EAAE,KAAK,CAAC;YACzD,MAAM,WAAW,GAAG,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC;YAC7C,MAAM,YAAY,GAAG,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;YAE/C,mCAAmC;YACnC,MAAM,cAAc,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,MAAM,gBAAgB,GAAG,EAAE,CAAC;YAE5B,IAAI,eAAe,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;gBACnD,gBAAgB,CAAC,IAAI,CAAC,iFAAiF,CAAC,CAAC;YAC3G,CAAC;YAED,OAAO;gBACL,GAAG,KAAK;gBACR,cAAc,EAAE,eAAe;gBAC/B,gBAAgB,EAAE,WAAW;gBAC7B,iBAAiB,EAAE,YAAY;gBAC/B,wBAAwB,EAAE,cAAc;gBACxC,mBAAmB,EAAE,gBAAgB;aACtC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;YAClD,4BAA4B;YAC5B,MAAM,eAAe,GAAG;mBACX,UAAU;eACd,cAAc;eACd,cAAc;wBACL,iBAAiB;sBACnB,YAAY,CAAC,MAAM;;EAEvC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAE7C,OAAO;gBACL,GAAG,KAAK;gBACR,cAAc,EAAE,eAAe;aAChC,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAAC,KAAgC;QAChE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;QAE5B,OAAO,CAAC,GAAG,CAAC,oCAAoC,SAAS,GAAG,CAAC,MAAM,CAAC,CAAC;QAErE,uBAAuB;QACvB,MAAM,YAAY,GAAG,EAAE,CAAC,CAAC,cAAc;QAEvC,OAAO;YACL,GAAG,KAAK;YACR,YAAY;YACZ,SAAS,EAAE,SAAS,GAAG,CAAC;SACzB,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,KAAgC;QAC/D,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;QAEtE,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QAEvC,yCAAyC;QACzC,IAAI,yBAAyB,GAAG,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;YAEnC,qCAAqC;YACrC,MAAM,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,iBAAiB,CAAC,CAAC;YAC/E,IAAI,kBAAkB,EAAE,CAAC;gBACvB,yBAAyB,IAAI,6CAA6C,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;YAC9H,CAAC;YAED,8BAA8B;YAC9B,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,cAAc,CAAC,CAAC;YACpE,IAAI,UAAU,EAAE,CAAC;gBACf,yBAAyB,IAAI,kCAAkC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;YAC3G,CAAC;YAED,kBAAkB;YAClB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC;YACvD,IAAI,MAAM,EAAE,CAAC;gBACX,yBAAyB,IAAI,kCAAkC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;YACvG,CAAC;QACH,CAAC;QAED,yCAAyC;QACzC,MAAM,gBAAgB,GAAG;EAC3B,yBAAyB;;;EAGzB,cAAc;;;EAGd,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;iBAE3B,YAAY,CAAC,IAAI;;;;;;;;;EAShC,yBAAyB,CAAC,CAAC,CAAC,kEAAkE,CAAC,CAAC,CAAC,EAAE;;EAEnG,yBAAyB,CAAC,CAAC,CAAC,iHAAiH,CAAC,CAAC,CAAC,EAAE;;;8CAGtG,CAAC;QAE3C,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACzE,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;YAC3D,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAiB,CAAC;YAE3C,eAAe;YACf,MAAM,KAAK,GAAI,QAAQ,CAAC,iBAAyB,EAAE,KAAK,CAAC;YACzD,MAAM,WAAW,GAAG,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC;YAC7C,MAAM,YAAY,GAAG,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;YAE/C,wBAAwB;YACxB,IAAI,eAAe,GAAa,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;gBAC/C,IAAI,SAAS,EAAE,CAAC;oBACd,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7C,CAAC;YACH,CAAC;YAAC,OAAO,UAAU,EAAE,CAAC;gBACpB,kCAAkC;gBAClC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClC,eAAe,GAAG,KAAK;qBACpB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;qBACxG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;qBACzE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;qBAC/B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACjB,CAAC;YAED,4CAA4C;YAC5C,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,eAAe,GAAG;oBAChB,0DAA0D;oBAC1D,+BAA+B;oBAC/B,8CAA8C;iBAC/C,CAAC;YACJ,CAAC;YAED,sCAAsC;YACtC,MAAM,cAAc,GAAG,yBAAyB,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,MAAM,gBAAgB,GAAG,EAAE,CAAC;YAE5B,IAAI,yBAAyB,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;gBAC7D,gBAAgB,CAAC,IAAI,CAAC,aAAa,eAAe,CAAC,MAAM,iEAAiE,CAAC,CAAC;YAC9H,CAAC;YAED,OAAO;gBACL,GAAG,KAAK;gBACR,eAAe;gBACf,gBAAgB,EAAE,CAAC,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC,GAAG,WAAW;gBAC7D,iBAAiB,EAAE,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,CAAC,GAAG,YAAY;gBAChE,wBAAwB,EAAE,cAAc;gBACxC,mBAAmB,EAAE,gBAAgB;aACtC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACjD,OAAO;gBACL,GAAG,KAAK;gBACR,eAAe,EAAE;oBACf,qDAAqD;oBACrD,kCAAkC;oBAClC,gCAAgC;iBACjC;aACF,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,KAAgC;QACzD,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QAExC,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,YAAY,CAAC,KAAgC;QACnD,wCAAwC;QACxC,MAAM,aAAa,GAAG,CAAC,CAAC;QACxB,MAAM,gBAAgB,GAAG,EAAE,CAAC;QAE5B,IAAI,KAAK,CAAC,SAAS,IAAI,aAAa,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,iCAAiC,aAAa,WAAW,CAAC,CAAC;YACvE,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,IAAI,KAAK,CAAC,YAAY,IAAI,gBAAgB,EAAE,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,kCAAkC,gBAAgB,YAAY,CAAC,CAAC;YAC5E,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,4BAA4B,KAAK,CAAC,SAAS,aAAa,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;QAC1F,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"} \ No newline at end of file diff --git a/dist/agents/jira-sub-agent.d.ts b/dist/agents/jira-sub-agent.d.ts new file mode 100644 index 0000000..e1bf685 --- /dev/null +++ b/dist/agents/jira-sub-agent.d.ts @@ -0,0 +1,477 @@ +/** + * Jira Sub-Agent (Peer Review Agent) + * + * This agent acts like an experienced senior developer reviewing a PR. + * It understands not just the code, but the business context from the Jira ticket. + * + * KEY PHILOSOPHY: + * Like a senior developer who deeply knows the codebase, this agent: + * 1. Mentally constructs test scenarios and edge cases (INTERNAL reasoning) + * 2. Uses those mental models to EVALUATE if the implementation is complete + * 3. Checks if changes might break other parts of the application + * 4. Reports FINDINGS, not suggestions for tests + * + * The test scenarios are the agent's internal thought process - like how a + * senior dev thinks "what about when X happens?" while reviewing code. + * The OUTPUT is the conclusion: "This doesn't handle X" or "X case is covered". + */ +import { z } from 'zod'; +import { IssueTicket } from '../types/issue-tracker.types.js'; +import { BaseLanguageModel } from '@langchain/core/language_models/base'; +import { AnalysisPrompt } from '../types/agent.types.js'; +/** + * Peer Review Execution Mode + * - EXECUTE: Execute prompts with LLM (CLI mode with API key) + * - PROMPT_ONLY: Return prompts for calling LLM to execute (MCP mode, no API key) + */ +export declare enum PeerReviewMode { + EXECUTE = "execute", + PROMPT_ONLY = "prompt_only" +} +/** + * Result when in PROMPT_ONLY mode (MCP) + */ +export interface PromptOnlyResult { + mode: 'prompt_only'; + context: JiraSubAgentContext; + prompts: AnalysisPrompt[]; + instructions: string; +} +declare const TicketQualitySchema: z.ZodObject<{ + overallScore: z.ZodNumber; + dimensions: z.ZodObject<{ + descriptionClarity: z.ZodNumber; + acceptanceCriteriaQuality: z.ZodNumber; + testabilityScore: z.ZodNumber; + scopeDefinition: z.ZodNumber; + technicalContext: z.ZodNumber; + visualDocumentation: z.ZodNumber; + completeness: z.ZodNumber; + }, "strip", z.ZodTypeAny, { + descriptionClarity: number; + acceptanceCriteriaQuality: number; + testabilityScore: number; + scopeDefinition: number; + technicalContext: number; + visualDocumentation: number; + completeness: number; + }, { + descriptionClarity: number; + acceptanceCriteriaQuality: number; + testabilityScore: number; + scopeDefinition: number; + technicalContext: number; + visualDocumentation: number; + completeness: number; + }>; + feedback: z.ZodObject<{ + strengths: z.ZodArray; + weaknesses: z.ZodArray; + suggestions: z.ZodArray; + }, "strip", z.ZodTypeAny, { + strengths: string[]; + weaknesses: string[]; + suggestions: string[]; + }, { + strengths: string[]; + weaknesses: string[]; + suggestions: string[]; + }>; + tier: z.ZodEnum<["excellent", "good", "adequate", "poor", "insufficient"]>; + reviewable: z.ZodBoolean; + reviewabilityReason: z.ZodString; +}, "strip", z.ZodTypeAny, { + overallScore: number; + dimensions: { + descriptionClarity: number; + acceptanceCriteriaQuality: number; + testabilityScore: number; + scopeDefinition: number; + technicalContext: number; + visualDocumentation: number; + completeness: number; + }; + feedback: { + strengths: string[]; + weaknesses: string[]; + suggestions: string[]; + }; + tier: "excellent" | "good" | "adequate" | "poor" | "insufficient"; + reviewable: boolean; + reviewabilityReason: string; +}, { + overallScore: number; + dimensions: { + descriptionClarity: number; + acceptanceCriteriaQuality: number; + testabilityScore: number; + scopeDefinition: number; + technicalContext: number; + visualDocumentation: number; + completeness: number; + }; + feedback: { + strengths: string[]; + weaknesses: string[]; + suggestions: string[]; + }; + tier: "excellent" | "good" | "adequate" | "poor" | "insufficient"; + reviewable: boolean; + reviewabilityReason: string; +}>; +/** + * Acceptance Criteria Validation - focuses on what IS and ISN'T covered + * + * IMPORTANT: The agent DERIVES its own acceptance criteria by analyzing: + * - The full ticket description + * - Any explicit AC field (if present, but don't rely on it) + * - The ticket type (bug vs feature has different expectations) + * - Technical context and constraints mentioned + * + * Like a senior dev who reads the whole ticket and thinks: + * "To implement this properly, I'd need to: 1) do X, 2) handle Y, 3) ensure Z" + */ +declare const AcceptanceCriteriaValidationSchema: z.ZodObject<{ + derivedRequirements: z.ZodArray; + importance: z.ZodEnum<["essential", "expected", "nice_to_have"]>; + }, "strip", z.ZodTypeAny, { + id: string; + requirement: string; + source: "description" | "explicit_ac" | "implied" | "ticket_type" | "technical_context"; + importance: "expected" | "essential" | "nice_to_have"; + }, { + id: string; + requirement: string; + source: "description" | "explicit_ac" | "implied" | "ticket_type" | "technical_context"; + importance: "expected" | "essential" | "nice_to_have"; + }>, "many">; + criteriaAnalysis: z.ZodArray; + criteriaText: z.ZodString; + status: z.ZodEnum<["met", "unmet", "partial", "unclear"]>; + confidence: z.ZodNumber; + evidence: z.ZodArray; + explanation: z.ZodString; + relatedFiles: z.ZodArray; + }, "strip", z.ZodTypeAny, { + status: "met" | "unmet" | "partial" | "unclear"; + confidence: number; + criteriaText: string; + evidence: string[]; + explanation: string; + relatedFiles: string[]; + criteriaId?: string | undefined; + }, { + status: "met" | "unmet" | "partial" | "unclear"; + confidence: number; + criteriaText: string; + evidence: string[]; + explanation: string; + relatedFiles: string[]; + criteriaId?: string | undefined; + }>, "many">; + compliancePercentage: z.ZodNumber; + gaps: z.ZodArray; + impact: z.ZodString; + }, "strip", z.ZodTypeAny, { + criteriaText: string; + gapDescription: string; + severity: "critical" | "major" | "minor"; + impact: string; + }, { + criteriaText: string; + gapDescription: string; + severity: "critical" | "major" | "minor"; + impact: string; + }>, "many">; + missingBehaviors: z.ZodArray; + partialImplementations: z.ZodArray; +}, "strip", z.ZodTypeAny, { + derivedRequirements: { + id: string; + requirement: string; + source: "description" | "explicit_ac" | "implied" | "ticket_type" | "technical_context"; + importance: "expected" | "essential" | "nice_to_have"; + }[]; + criteriaAnalysis: { + status: "met" | "unmet" | "partial" | "unclear"; + confidence: number; + criteriaText: string; + evidence: string[]; + explanation: string; + relatedFiles: string[]; + criteriaId?: string | undefined; + }[]; + compliancePercentage: number; + gaps: { + criteriaText: string; + gapDescription: string; + severity: "critical" | "major" | "minor"; + impact: string; + }[]; + missingBehaviors: string[]; + partialImplementations: string[]; +}, { + derivedRequirements: { + id: string; + requirement: string; + source: "description" | "explicit_ac" | "implied" | "ticket_type" | "technical_context"; + importance: "expected" | "essential" | "nice_to_have"; + }[]; + criteriaAnalysis: { + status: "met" | "unmet" | "partial" | "unclear"; + confidence: number; + criteriaText: string; + evidence: string[]; + explanation: string; + relatedFiles: string[]; + criteriaId?: string | undefined; + }[]; + compliancePercentage: number; + gaps: { + criteriaText: string; + gapDescription: string; + severity: "critical" | "major" | "minor"; + impact: string; + }[]; + missingBehaviors: string[]; + partialImplementations: string[]; +}>; +/** + * Peer Review Analysis - the senior developer's verdict + */ +declare const PeerReviewAnalysisSchema: z.ZodObject<{ + implementationCompleteness: z.ZodNumber; + qualityScore: z.ZodNumber; + readyForReview: z.ZodBoolean; + blockers: z.ZodArray; + }, "strip", z.ZodTypeAny, { + issue: string; + reason: string; + location?: string | undefined; + }, { + issue: string; + reason: string; + location?: string | undefined; + }>, "many">; + warnings: z.ZodArray; + }, "strip", z.ZodTypeAny, { + issue: string; + reason: string; + location?: string | undefined; + }, { + issue: string; + reason: string; + location?: string | undefined; + }>, "many">; + recommendations: z.ZodArray; + scopeAnalysis: z.ZodObject<{ + inScope: z.ZodArray; + outOfScope: z.ZodArray; + scopeCreepRisk: z.ZodBoolean; + scopeCreepDetails: z.ZodOptional; + }, "strip", z.ZodTypeAny, { + inScope: string[]; + outOfScope: string[]; + scopeCreepRisk: boolean; + scopeCreepDetails?: string | undefined; + }, { + inScope: string[]; + outOfScope: string[]; + scopeCreepRisk: boolean; + scopeCreepDetails?: string | undefined; + }>; + regressionRisks: z.ZodArray; + reasoning: z.ZodString; + }, "strip", z.ZodTypeAny, { + reasoning: string; + risk: string; + affectedArea: string; + likelihood: "high" | "medium" | "low"; + }, { + reasoning: string; + risk: string; + affectedArea: string; + likelihood: "high" | "medium" | "low"; + }>, "many">; + uncoveredScenarios: z.ZodArray; + relatedCriteria: z.ZodOptional; + }, "strip", z.ZodTypeAny, { + impact: "critical" | "major" | "minor"; + scenario: string; + relatedCriteria?: string | undefined; + }, { + impact: "critical" | "major" | "minor"; + scenario: string; + relatedCriteria?: string | undefined; + }>, "many">; + verdict: z.ZodObject<{ + summary: z.ZodString; + recommendation: z.ZodEnum<["approve", "request_changes", "needs_discussion"]>; + confidenceLevel: z.ZodNumber; + }, "strip", z.ZodTypeAny, { + recommendation: "approve" | "request_changes" | "needs_discussion"; + summary: string; + confidenceLevel: number; + }, { + recommendation: "approve" | "request_changes" | "needs_discussion"; + summary: string; + confidenceLevel: number; + }>; +}, "strip", z.ZodTypeAny, { + recommendations: string[]; + implementationCompleteness: number; + qualityScore: number; + readyForReview: boolean; + blockers: { + issue: string; + reason: string; + location?: string | undefined; + }[]; + warnings: { + issue: string; + reason: string; + location?: string | undefined; + }[]; + scopeAnalysis: { + inScope: string[]; + outOfScope: string[]; + scopeCreepRisk: boolean; + scopeCreepDetails?: string | undefined; + }; + regressionRisks: { + reasoning: string; + risk: string; + affectedArea: string; + likelihood: "high" | "medium" | "low"; + }[]; + uncoveredScenarios: { + impact: "critical" | "major" | "minor"; + scenario: string; + relatedCriteria?: string | undefined; + }[]; + verdict: { + recommendation: "approve" | "request_changes" | "needs_discussion"; + summary: string; + confidenceLevel: number; + }; +}, { + recommendations: string[]; + implementationCompleteness: number; + qualityScore: number; + readyForReview: boolean; + blockers: { + issue: string; + reason: string; + location?: string | undefined; + }[]; + warnings: { + issue: string; + reason: string; + location?: string | undefined; + }[]; + scopeAnalysis: { + inScope: string[]; + outOfScope: string[]; + scopeCreepRisk: boolean; + scopeCreepDetails?: string | undefined; + }; + regressionRisks: { + reasoning: string; + risk: string; + affectedArea: string; + likelihood: "high" | "medium" | "low"; + }[]; + uncoveredScenarios: { + impact: "critical" | "major" | "minor"; + scenario: string; + relatedCriteria?: string | undefined; + }[]; + verdict: { + recommendation: "approve" | "request_changes" | "needs_discussion"; + summary: string; + confidenceLevel: number; + }; +}>; +export type TicketQualityRating = z.infer; +export type AcceptanceCriteriaValidation = z.infer; +export type PeerReviewAnalysis = z.infer; +export interface JiraSubAgentResult { + ticketQuality: TicketQualityRating; + acValidation?: AcceptanceCriteriaValidation; + peerReview: PeerReviewAnalysis; +} +export interface JiraSubAgentContext { + ticket: IssueTicket; + prTitle: string; + prDescription?: string; + diff: string; + files: Array<{ + path: string; + additions: number; + deletions: number; + status: string; + }>; + prSummary?: string; + prRisks?: string[]; +} +export declare class JiraSubAgent { + private mode; + private llm?; + constructor(mode?: PeerReviewMode, llm?: BaseLanguageModel); + /** + * Analyze a ticket and PR, providing comprehensive peer review + * Returns either executed results (EXECUTE mode) or prompts (PROMPT_ONLY mode) + */ + analyze(context: JiraSubAgentContext): Promise; + /** + * Build prompts without executing (MCP mode) + */ + private buildPrompts; + /** + * Execute analysis with LLM (CLI mode) + */ + private executeAnalysis; + /** + * Build ticket quality prompt (PROMPT_ONLY mode) + */ + private buildTicketQualityPrompt; + /** + * Build AC validation prompt (PROMPT_ONLY mode) + */ + private buildACValidationPrompt; + /** + * Build peer review prompt (PROMPT_ONLY mode) + */ + private buildPeerReviewPrompt; + /** + * Rate the quality of a Jira ticket (EXECUTE mode) + */ + rateTicketQuality(ticket: IssueTicket): Promise; + /** + * Validate acceptance criteria against PR changes + */ + validateAcceptanceCriteria(context: JiraSubAgentContext): Promise; + /** + * Generate comprehensive peer review analysis + */ + generatePeerReview(context: JiraSubAgentContext, ticketQuality: TicketQualityRating, acValidation?: AcceptanceCriteriaValidation): Promise; +} +export {}; diff --git a/dist/agents/jira-sub-agent.js b/dist/agents/jira-sub-agent.js new file mode 100644 index 0000000..9ca7303 --- /dev/null +++ b/dist/agents/jira-sub-agent.js @@ -0,0 +1,663 @@ +/** + * Jira Sub-Agent (Peer Review Agent) + * + * This agent acts like an experienced senior developer reviewing a PR. + * It understands not just the code, but the business context from the Jira ticket. + * + * KEY PHILOSOPHY: + * Like a senior developer who deeply knows the codebase, this agent: + * 1. Mentally constructs test scenarios and edge cases (INTERNAL reasoning) + * 2. Uses those mental models to EVALUATE if the implementation is complete + * 3. Checks if changes might break other parts of the application + * 4. Reports FINDINGS, not suggestions for tests + * + * The test scenarios are the agent's internal thought process - like how a + * senior dev thinks "what about when X happens?" while reviewing code. + * The OUTPUT is the conclusion: "This doesn't handle X" or "X case is covered". + */ +import { ChatPromptTemplate } from '@langchain/core/prompts'; +import { StructuredOutputParser } from '@langchain/core/output_parsers'; +import { z } from 'zod'; +// ========== Execution Modes ========== +/** + * Peer Review Execution Mode + * - EXECUTE: Execute prompts with LLM (CLI mode with API key) + * - PROMPT_ONLY: Return prompts for calling LLM to execute (MCP mode, no API key) + */ +export var PeerReviewMode; +(function (PeerReviewMode) { + PeerReviewMode["EXECUTE"] = "execute"; + PeerReviewMode["PROMPT_ONLY"] = "prompt_only"; +})(PeerReviewMode || (PeerReviewMode = {})); +// ========== Output Schemas ========== +const TicketQualitySchema = z.object({ + overallScore: z.number().min(0).max(100).describe('Overall ticket quality score'), + dimensions: z.object({ + descriptionClarity: z.number().min(0).max(100), + acceptanceCriteriaQuality: z.number().min(0).max(100), + testabilityScore: z.number().min(0).max(100), + scopeDefinition: z.number().min(0).max(100), + technicalContext: z.number().min(0).max(100), + visualDocumentation: z.number().min(0).max(100), + completeness: z.number().min(0).max(100), + }), + feedback: z.object({ + strengths: z.array(z.string()), + weaknesses: z.array(z.string()), + suggestions: z.array(z.string()), + }), + tier: z.enum(['excellent', 'good', 'adequate', 'poor', 'insufficient']), + reviewable: z.boolean(), + reviewabilityReason: z.string(), +}); +/** + * Acceptance Criteria Validation - focuses on what IS and ISN'T covered + * + * IMPORTANT: The agent DERIVES its own acceptance criteria by analyzing: + * - The full ticket description + * - Any explicit AC field (if present, but don't rely on it) + * - The ticket type (bug vs feature has different expectations) + * - Technical context and constraints mentioned + * + * Like a senior dev who reads the whole ticket and thinks: + * "To implement this properly, I'd need to: 1) do X, 2) handle Y, 3) ensure Z" + */ +const AcceptanceCriteriaValidationSchema = z.object({ + // The agent's derived understanding of what needs to be implemented + derivedRequirements: z.array(z.object({ + id: z.string(), + requirement: z.string().describe('What the agent derived needs to be done'), + source: z.enum(['description', 'explicit_ac', 'implied', 'ticket_type', 'technical_context']) + .describe('Where this requirement was derived from'), + importance: z.enum(['essential', 'expected', 'nice_to_have']), + })).describe('Requirements derived by analyzing the full ticket, not just AC field'), + // Analysis of each derived requirement against the PR + criteriaAnalysis: z.array(z.object({ + criteriaId: z.string().optional(), + criteriaText: z.string(), + status: z.enum(['met', 'unmet', 'partial', 'unclear']), + confidence: z.number().min(0).max(100), + evidence: z.array(z.string()).describe('Code evidence showing coverage or lack thereof'), + explanation: z.string().describe('Why this criteria is/isnt met'), + relatedFiles: z.array(z.string()), + })), + compliancePercentage: z.number().min(0).max(100), + gaps: z.array(z.object({ + criteriaText: z.string(), + gapDescription: z.string().describe('What specific functionality is missing'), + severity: z.enum(['critical', 'major', 'minor']), + impact: z.string().describe('What will happen if this gap is not addressed'), + })), + // Internal reasoning exposed as findings, not suggestions + missingBehaviors: z.array(z.string()).describe('Behaviors that should exist but dont'), + partialImplementations: z.array(z.string()).describe('Features that are started but incomplete'), +}); +/** + * Peer Review Analysis - the senior developer's verdict + */ +const PeerReviewAnalysisSchema = z.object({ + implementationCompleteness: z.number().min(0).max(100), + qualityScore: z.number().min(0).max(100), + readyForReview: z.boolean(), + // Critical findings that block merge + blockers: z.array(z.object({ + issue: z.string(), + reason: z.string(), + location: z.string().optional().describe('File or component affected'), + })), + // Important issues that should be fixed + warnings: z.array(z.object({ + issue: z.string(), + reason: z.string(), + location: z.string().optional(), + })), + // Nice-to-have improvements + recommendations: z.array(z.string()), + // Scope analysis + scopeAnalysis: z.object({ + inScope: z.array(z.string()), + outOfScope: z.array(z.string()), + scopeCreepRisk: z.boolean(), + scopeCreepDetails: z.string().optional(), + }), + // Potential regression analysis - what might break + regressionRisks: z.array(z.object({ + risk: z.string().describe('What could break'), + affectedArea: z.string().describe('Part of the app that might be affected'), + likelihood: z.enum(['high', 'medium', 'low']), + reasoning: z.string().describe('Why this might happen'), + })), + // Uncovered scenarios identified during review (findings, not suggestions) + uncoveredScenarios: z.array(z.object({ + scenario: z.string().describe('A scenario that isnt handled'), + impact: z.enum(['critical', 'major', 'minor']), + relatedCriteria: z.string().optional(), + })), + // Final verdict + verdict: z.object({ + summary: z.string().describe('One paragraph summary of the review'), + recommendation: z.enum(['approve', 'request_changes', 'needs_discussion']), + confidenceLevel: z.number().min(0).max(100), + }), +}); +// ========== Prompts ========== +const TICKET_QUALITY_PROMPT = `You are an expert at evaluating Jira tickets and user stories. +Analyze the following ticket and rate its quality based on industry best practices. + +TICKET INFORMATION: +Key: {ticketKey} +Type: {ticketType} +Title: {ticketTitle} +Description: +{ticketDescription} + +Acceptance Criteria: +{acceptanceCriteria} + +Test Scenarios Defined: {testScenarios} +Has Screenshots/Mockups: {hasScreenshots} +Has Diagrams: {hasDiagrams} +Story Points: {storyPoints} +Labels: {labels} +Components: {components} + +EVALUATION CRITERIA: +1. Description Clarity (0-100): Is the description clear, complete, and unambiguous? +2. Acceptance Criteria Quality (0-100): Are ACs specific, measurable, achievable, and testable (SMART)? +3. Testability Score (0-100): Can this ticket be tested? Are expected behaviors clear? +4. Scope Definition (0-100): Is the scope well-defined and bounded? No scope creep potential? +5. Technical Context (0-100): Are technical requirements, constraints, and dependencies clear? +6. Visual Documentation (0-100): Are there screenshots, mockups, or diagrams where needed? +7. Completeness (0-100): Overall ticket completeness - nothing critical missing? + +QUALITY TIERS: +- excellent (85-100): Exemplary ticket, can be implemented with high confidence +- good (70-84): Well-written ticket with minor gaps +- adequate (50-69): Passable but has notable gaps that may cause issues +- poor (25-49): Significant issues, needs improvement before implementation +- insufficient (0-24): Cannot be implemented reliably, needs major rework + +REVIEWABILITY: +A ticket is "reviewable" if there's enough information to meaningfully derive what needs +to be implemented. This does NOT require an explicit acceptance criteria field! + +A ticket is REVIEWABLE if: +- The description explains what needs to be done (even briefly) +- The title + type give enough context to understand the goal +- A senior developer could reasonably derive requirements from it + +A ticket is NOT REVIEWABLE if: +- It's just a title with no description (e.g., "Fix bug" with nothing else) +- It's too vague to derive any concrete requirements +- There's literally not enough info to know what "done" looks like + +Remember: Many good tickets have detailed descriptions but empty AC fields. +The key is whether YOU can derive what needs to be built. + +{format_instructions}`; +const AC_VALIDATION_PROMPT = `You are a SENIOR DEVELOPER with deep knowledge of this codebase reviewing a PR. + +Your task: Understand what this ticket requires, then evaluate if the PR implements it correctly. + +CRITICAL: DO NOT just rely on the "Acceptance Criteria" field. Many tickets have empty AC or +poorly written AC. You must DERIVE your own understanding of what needs to be done by reading: +- The full description +- The ticket type (bug fix has different needs than a feature) +- Any technical context mentioned +- The implicit requirements (what any experienced dev would know is needed) + +Think like an experienced dev who reads a ticket and thinks: +"Okay, to implement this properly I need to: handle X, add Y, make sure Z works..." + +JIRA TICKET: +Key: {ticketKey} +Type: {ticketType} +Title: {ticketTitle} + +FULL DESCRIPTION (analyze this carefully): +{ticketDescription} + +EXPLICIT ACCEPTANCE CRITERIA (may be empty or incomplete - don't rely solely on this): +{acceptanceCriteria} + +PR INFORMATION: +Title: {prTitle} +Description: {prDescription} + +FILES CHANGED: +{filesChanged} + +CODE DIFF: +{diff} + +PREVIOUS PR ANALYSIS SUMMARY: +{prSummary} + +YOUR TASK: + +1. DERIVE REQUIREMENTS: + First, read the entire ticket and derive what actually needs to be implemented. + For each requirement you identify, note: + - What the requirement is + - Where you derived it from (description, explicit AC, implied by ticket type, technical context) + - How essential it is (essential, expected, nice-to-have) + + Don't just copy the AC field - THINK about what's really needed. + A ticket saying "Add login button" implies: the button should be visible, clickable, + trigger auth flow, handle errors, etc. + +2. VALIDATE EACH REQUIREMENT: + For each derived requirement: + - Is it MET, UNMET, PARTIAL, or UNCLEAR in the code? + - Provide CODE EVIDENCE + - Explain your reasoning + +3. IDENTIFY GAPS: + What's missing? What behaviors should exist but don't? + Think through scenarios: "What if the user does X?" "What about error case Y?" + +Report FINDINGS, not suggestions. Like a senior dev saying: +"This doesn't handle the case when the user is logged out" + +{format_instructions}`; +const PEER_REVIEW_PROMPT = `You are a SENIOR DEVELOPER doing a thorough peer review. + +You've been with this team for years. You know where the bodies are buried. +You think about: +- Does this actually solve the problem in the ticket? +- What might this break in other parts of the app? +- Are there scenarios the developer didn't consider? +- Is this ready for production? + +JIRA TICKET: +Key: {ticketKey} +Type: {ticketType} +Title: {ticketTitle} +Description: {ticketDescription} +Acceptance Criteria: {acceptanceCriteria} + +PR INFORMATION: +Title: {prTitle} +Description: {prDescription} + +FILES CHANGED: +{filesChanged} + +DIFF SUMMARY: +{diff} + +EXISTING PR ANALYSIS: +Summary: {prSummary} +Risks Identified: {prRisks} + +TICKET QUALITY ASSESSMENT: +Overall Score: {ticketQualityScore}/100 +Reviewable: {isReviewable} + +AC VALIDATION RESULTS: +Compliance: {acCompliancePercentage}% +Gaps Found: {gapsFound} + +YOUR PEER REVIEW TASK: + +1. IMPLEMENTATION COMPLETENESS (0-100): + Does this PR fully implement what the ticket asks for? + +2. QUALITY SCORE (0-100): + Code quality + requirements adherence combined + +3. READY FOR REVIEW: + Would you approve this or request changes? + +4. BLOCKERS: + Critical issues - things that MUST be fixed before merge + (missing functionality, bugs, security issues) + +5. WARNINGS: + Important issues - things that SHOULD be fixed + (edge cases not handled, potential bugs) + +6. RECOMMENDATIONS: + Nice-to-haves for improvement + +7. SCOPE ANALYSIS: + - What's in scope vs out of scope? + - Is there scope creep? + +8. REGRESSION RISKS: + Think: "What else in the app might this break?" + - Consider dependencies, shared code, side effects + - Think about how this interacts with existing features + +9. UNCOVERED SCENARIOS: + As a senior dev, you mentally run through scenarios: + - "What if the user does X?" + - "What about when Y is null?" + - "What happens during Z error condition?" + + Report which scenarios you identified that AREN'T handled. + Don't suggest tests - just flag what's missing. + +10. FINAL VERDICT: + Give your honest assessment: + - APPROVE: Ready to merge (maybe minor nits) + - REQUEST_CHANGES: Needs work before merge + - NEEDS_DISCUSSION: Architectural concerns to discuss + +{format_instructions}`; +// ========== Agent Class ========== +export class JiraSubAgent { + mode; + llm; + constructor(mode = PeerReviewMode.EXECUTE, llm) { + this.mode = mode; + this.llm = llm; + // Validate: EXECUTE mode requires LLM + if (mode === PeerReviewMode.EXECUTE && !llm) { + throw new Error('JiraSubAgent: LLM is required when mode is EXECUTE'); + } + } + /** + * Analyze a ticket and PR, providing comprehensive peer review + * Returns either executed results (EXECUTE mode) or prompts (PROMPT_ONLY mode) + */ + async analyze(context) { + if (this.mode === PeerReviewMode.PROMPT_ONLY) { + return this.buildPrompts(context); + } + else { + return this.executeAnalysis(context); + } + } + /** + * Build prompts without executing (MCP mode) + */ + buildPrompts(context) { + const prompts = []; + // Step 1: Build ticket quality prompt + prompts.push(this.buildTicketQualityPrompt(context.ticket)); + // Step 2: Build AC validation prompt (always - agent derives requirements) + prompts.push(this.buildACValidationPrompt(context)); + // Step 3: Build peer review prompt + // Note: In PROMPT_ONLY mode, we don't know ticketQuality yet, + // so we include it as a dependency instruction + prompts.push(this.buildPeerReviewPrompt(context)); + return { + mode: 'prompt_only', + context, + prompts, + instructions: 'Execute these prompts sequentially. ' + + 'Pass the output of ticketQuality to peerReview as ticketQualityScore. ' + + 'Parse each response according to the provided schema.' + }; + } + /** + * Execute analysis with LLM (CLI mode) + */ + async executeAnalysis(context) { + // Step 1: Rate ticket quality + const ticketQuality = await this.rateTicketQuality(context.ticket); + // Step 2: Derive requirements and validate against PR + // NOTE: We analyze even if there's no explicit AC field - the agent derives + // requirements from the full ticket (description, title, type, context) + let acValidation; + if (ticketQuality.reviewable) { + // The agent will derive its own requirements from the ticket + // Don't skip just because acceptanceCriteriaList is empty + acValidation = await this.validateAcceptanceCriteria(context); + } + // Step 3: Generate peer review analysis + const peerReview = await this.generatePeerReview(context, ticketQuality, acValidation); + return { + ticketQuality, + acValidation, + peerReview, + }; + } + /** + * Build ticket quality prompt (PROMPT_ONLY mode) + */ + buildTicketQualityPrompt(ticket) { + const parser = StructuredOutputParser.fromZodSchema(TicketQualitySchema); + const inputs = { + ticketKey: ticket.key, + ticketType: ticket.type, + ticketTitle: ticket.title, + ticketDescription: ticket.description || 'No description provided', + acceptanceCriteria: ticket.acceptanceCriteria || + ticket.acceptanceCriteriaList?.join('\n') || + 'No acceptance criteria defined', + testScenarios: ticket.testScenarios?.join(', ') || 'None defined', + hasScreenshots: ticket.hasScreenshots ? 'Yes' : 'No', + hasDiagrams: ticket.hasDiagrams ? 'Yes' : 'No', + storyPoints: ticket.storyPoints?.toString() || 'Not estimated', + labels: ticket.labels.join(', ') || 'None', + components: ticket.components.join(', ') || 'None', + format_instructions: parser.getFormatInstructions(), + }; + // Fill in the template + let prompt = TICKET_QUALITY_PROMPT; + for (const [key, value] of Object.entries(inputs)) { + prompt = prompt.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value)); + } + return { + step: 'ticketQuality', + prompt, + schema: TicketQualitySchema, + formatInstructions: parser.getFormatInstructions(), + inputs, + instructions: 'Analyze the ticket quality and return a JSON object matching the schema', + }; + } + /** + * Build AC validation prompt (PROMPT_ONLY mode) + */ + buildACValidationPrompt(context) { + const parser = StructuredOutputParser.fromZodSchema(AcceptanceCriteriaValidationSchema); + // Format acceptance criteria with IDs + const acList = context.ticket.acceptanceCriteriaList || []; + const formattedAC = acList + .map((ac, i) => `AC-${i + 1}: ${ac}`) + .join('\n'); + // Format files changed + const filesChanged = context.files + .map((f) => `${f.path} (+${f.additions}/-${f.deletions}) [${f.status}]`) + .join('\n'); + // Truncate diff if too long + const maxDiffLength = 15000; + const truncatedDiff = context.diff.length > maxDiffLength + ? context.diff.substring(0, maxDiffLength) + '\n... [diff truncated]' + : context.diff; + const inputs = { + ticketKey: context.ticket.key, + ticketType: context.ticket.type, + ticketTitle: context.ticket.title, + ticketDescription: context.ticket.description?.substring(0, 2000) || 'No description', + acceptanceCriteria: formattedAC || 'No acceptance criteria defined', + prTitle: context.prTitle, + prDescription: context.prDescription || 'No description', + filesChanged, + diff: truncatedDiff, + prSummary: context.prSummary || 'No summary available', + format_instructions: parser.getFormatInstructions(), + }; + // Fill in the template + let prompt = AC_VALIDATION_PROMPT; + for (const [key, value] of Object.entries(inputs)) { + prompt = prompt.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value)); + } + return { + step: 'acValidation', + prompt, + schema: AcceptanceCriteriaValidationSchema, + formatInstructions: parser.getFormatInstructions(), + inputs, + instructions: 'Validate acceptance criteria coverage and return a JSON object matching the schema', + }; + } + /** + * Build peer review prompt (PROMPT_ONLY mode) + */ + buildPeerReviewPrompt(context) { + const parser = StructuredOutputParser.fromZodSchema(PeerReviewAnalysisSchema); + // Format files changed + const filesChanged = context.files + .map((f) => `${f.path} (+${f.additions}/-${f.deletions}) [${f.status}]`) + .join('\n'); + // Truncate diff if too long + const maxDiffLength = 10000; + const truncatedDiff = context.diff.length > maxDiffLength + ? context.diff.substring(0, maxDiffLength) + '\n... [diff truncated]' + : context.diff; + const inputs = { + ticketKey: context.ticket.key, + ticketType: context.ticket.type, + ticketTitle: context.ticket.title, + ticketDescription: context.ticket.description?.substring(0, 2000) || 'No description', + acceptanceCriteria: context.ticket.acceptanceCriteria || + context.ticket.acceptanceCriteriaList?.join('\n') || + 'None defined', + prTitle: context.prTitle, + prDescription: context.prDescription || 'No description', + filesChanged, + diff: truncatedDiff, + prSummary: context.prSummary || 'No summary available', + prRisks: context.prRisks?.join(', ') || 'None identified', + // Placeholders for ticket quality - will be filled by calling LLM + ticketQualityScore: '{RESULT_FROM_ticketQuality.overallScore}', + isReviewable: '{RESULT_FROM_ticketQuality.reviewable}', + acCompliancePercentage: '{RESULT_FROM_acValidation.compliancePercentage}', + gapsFound: '{RESULT_FROM_acValidation.gaps}', + format_instructions: parser.getFormatInstructions(), + }; + // Fill in the template + let prompt = PEER_REVIEW_PROMPT; + for (const [key, value] of Object.entries(inputs)) { + prompt = prompt.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value)); + } + return { + step: 'peerReview', + prompt, + schema: PeerReviewAnalysisSchema, + formatInstructions: parser.getFormatInstructions(), + inputs, + instructions: 'Perform peer review analysis and return a JSON object matching the schema', + }; + } + /** + * Rate the quality of a Jira ticket (EXECUTE mode) + */ + async rateTicketQuality(ticket) { + if (!this.llm) { + throw new Error('LLM is required for rateTicketQuality in EXECUTE mode'); + } + const parser = StructuredOutputParser.fromZodSchema(TicketQualitySchema); + const prompt = ChatPromptTemplate.fromTemplate(TICKET_QUALITY_PROMPT); + const chain = prompt.pipe(this.llm); + const response = await chain.invoke({ + ticketKey: ticket.key, + ticketType: ticket.type, + ticketTitle: ticket.title, + ticketDescription: ticket.description || 'No description provided', + acceptanceCriteria: ticket.acceptanceCriteria || + ticket.acceptanceCriteriaList?.join('\n') || + 'No acceptance criteria defined', + testScenarios: ticket.testScenarios?.join(', ') || 'None defined', + hasScreenshots: ticket.hasScreenshots ? 'Yes' : 'No', + hasDiagrams: ticket.hasDiagrams ? 'Yes' : 'No', + storyPoints: ticket.storyPoints?.toString() || 'Not estimated', + labels: ticket.labels.join(', ') || 'None', + components: ticket.components.join(', ') || 'None', + format_instructions: parser.getFormatInstructions(), + }); + const content = typeof response === 'string' ? response : response.content?.toString() || ''; + return parser.parse(content); + } + /** + * Validate acceptance criteria against PR changes + */ + async validateAcceptanceCriteria(context) { + if (!this.llm) { + throw new Error('LLM is required for validateAcceptanceCriteria in EXECUTE mode'); + } + const parser = StructuredOutputParser.fromZodSchema(AcceptanceCriteriaValidationSchema); + const prompt = ChatPromptTemplate.fromTemplate(AC_VALIDATION_PROMPT); + const chain = prompt.pipe(this.llm); + // Format acceptance criteria with IDs + const acList = context.ticket.acceptanceCriteriaList || []; + const formattedAC = acList + .map((ac, i) => `AC-${i + 1}: ${ac}`) + .join('\n'); + // Format files changed + const filesChanged = context.files + .map((f) => `${f.path} (+${f.additions}/-${f.deletions}) [${f.status}]`) + .join('\n'); + // Truncate diff if too long + const maxDiffLength = 15000; + const truncatedDiff = context.diff.length > maxDiffLength + ? context.diff.substring(0, maxDiffLength) + '\n... [diff truncated]' + : context.diff; + const response = await chain.invoke({ + ticketKey: context.ticket.key, + ticketType: context.ticket.type, + ticketTitle: context.ticket.title, + ticketDescription: context.ticket.description?.substring(0, 2000) || 'No description', + acceptanceCriteria: formattedAC || 'No acceptance criteria defined', + prTitle: context.prTitle, + prDescription: context.prDescription || 'No description', + filesChanged, + diff: truncatedDiff, + prSummary: context.prSummary || 'No summary available', + format_instructions: parser.getFormatInstructions(), + }); + const content = typeof response === 'string' ? response : response.content?.toString() || ''; + return parser.parse(content); + } + /** + * Generate comprehensive peer review analysis + */ + async generatePeerReview(context, ticketQuality, acValidation) { + if (!this.llm) { + throw new Error('LLM is required for generatePeerReview in EXECUTE mode'); + } + const parser = StructuredOutputParser.fromZodSchema(PeerReviewAnalysisSchema); + const prompt = ChatPromptTemplate.fromTemplate(PEER_REVIEW_PROMPT); + const chain = prompt.pipe(this.llm); + // Format files changed + const filesChanged = context.files + .map((f) => `${f.path} (+${f.additions}/-${f.deletions}) [${f.status}]`) + .join('\n'); + // Truncate diff if too long + const maxDiffLength = 10000; + const truncatedDiff = context.diff.length > maxDiffLength + ? context.diff.substring(0, maxDiffLength) + '\n... [diff truncated]' + : context.diff; + // Format gaps found + const gapsFound = acValidation?.gaps + .map((g) => `- ${g.criteriaText}: ${g.gapDescription}`) + .join('\n') || 'None identified'; + const response = await chain.invoke({ + ticketKey: context.ticket.key, + ticketType: context.ticket.type, + ticketTitle: context.ticket.title, + ticketDescription: context.ticket.description?.substring(0, 2000) || 'No description', + acceptanceCriteria: context.ticket.acceptanceCriteria || + context.ticket.acceptanceCriteriaList?.join('\n') || + 'None defined', + prTitle: context.prTitle, + prDescription: context.prDescription || 'No description', + filesChanged, + diff: truncatedDiff, + prSummary: context.prSummary || 'No summary available', + prRisks: context.prRisks?.join(', ') || 'None identified', + ticketQualityScore: ticketQuality.overallScore, + isReviewable: ticketQuality.reviewable ? 'Yes' : 'No', + acCompliancePercentage: acValidation?.compliancePercentage ?? 'N/A', + gapsFound, + format_instructions: parser.getFormatInstructions(), + }); + const content = typeof response === 'string' ? response : response.content?.toString() || ''; + return parser.parse(content); + } +} +//# sourceMappingURL=jira-sub-agent.js.map \ No newline at end of file diff --git a/dist/agents/jira-sub-agent.js.map b/dist/agents/jira-sub-agent.js.map new file mode 100644 index 0000000..07a5d4e --- /dev/null +++ b/dist/agents/jira-sub-agent.js.map @@ -0,0 +1 @@ +{"version":3,"file":"jira-sub-agent.js","sourceRoot":"","sources":["../../src/agents/jira-sub-agent.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/agents/pr-analyzer-agent.d.ts b/dist/agents/pr-analyzer-agent.d.ts index ffb301c..a4a556d 100644 --- a/dist/agents/pr-analyzer-agent.d.ts +++ b/dist/agents/pr-analyzer-agent.d.ts @@ -2,28 +2,42 @@ * PR Analyzer Agent * LangChain-based agent for intelligent PR analysis */ +import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { BasePRAgentWorkflow } from './base-pr-agent-workflow.js'; -import { AgentContext, AgentResult, AgentMetadata, AnalysisMode } from '../types/agent.types.js'; +import { AgentContext, AgentResultOrPrompts, AgentMetadata, AnalysisMode, ExecutionMode } from '../types/agent.types.js'; import { ProviderOptions } from '../providers/index.js'; +/** + * Extended options that allow passing a pre-configured model + * Used by MCP server to pass its underlying LLM model + */ +export interface PRAnalyzerOptions extends ProviderOptions { + /** Execution mode: EXECUTE (with API key) or PROMPT_ONLY (return prompts) */ + mode?: ExecutionMode; + /** Pre-configured LangChain model (for MCP server pass-through) */ + chatModel?: BaseChatModel; +} /** * PR Analysis Agent using LangChain and LangGraph */ export declare class PRAnalyzerAgent extends BasePRAgentWorkflow { - constructor(options?: ProviderOptions); + constructor(options?: PRAnalyzerOptions); /** * Get agent metadata */ getMetadata(): AgentMetadata; /** * Analyze a PR with full agent workflow + * Returns either executed results (EXECUTE mode) or prompts (PROMPT_ONLY mode) */ analyze(diff: string, title?: string, mode?: AnalysisMode, options?: { useArchDocs?: boolean; repoPath?: string; + repoOwner?: string; + repoName?: string; language?: string; framework?: string; enableStaticAnalysis?: boolean; - }): Promise; + }): Promise; /** * Quick analysis without refinement */ @@ -33,14 +47,14 @@ export declare class PRAnalyzerAgent extends BasePRAgentWorkflow { language?: string; framework?: string; enableStaticAnalysis?: boolean; - }): Promise; + }): Promise; /** * Analyze specific files only */ analyzeFiles(diff: string, filePaths: string[], options?: { useArchDocs?: boolean; repoPath?: string; - }): Promise; + }): Promise; /** * Check if agent can execute with given context */ @@ -53,7 +67,7 @@ export declare class PRAnalyzerAgent extends BasePRAgentWorkflow { /** * Factory function to create PR analyzer agent */ -export declare function createPRAnalyzerAgent(options?: ProviderOptions): PRAnalyzerAgent; +export declare function createPRAnalyzerAgent(options?: PRAnalyzerOptions): PRAnalyzerAgent; /** * Legacy factory function for backward compatibility * @deprecated Use PRAnalyzerAgent constructor with ProviderOptions instead diff --git a/dist/agents/pr-analyzer-agent.js b/dist/agents/pr-analyzer-agent.js index 4d76f9f..f3afbd5 100644 --- a/dist/agents/pr-analyzer-agent.js +++ b/dist/agents/pr-analyzer-agent.js @@ -3,6 +3,7 @@ * LangChain-based agent for intelligent PR analysis */ import { BasePRAgentWorkflow } from './base-pr-agent-workflow.js'; +import { ExecutionMode } from '../types/agent.types.js'; import { parseDiff } from '../tools/pr-analysis-tools.js'; import { ProviderFactory } from '../providers/index.js'; import { parseAllArchDocs, archDocsExists } from '../utils/arch-docs-parser.js'; @@ -12,14 +13,27 @@ import { buildArchDocsContext } from '../utils/arch-docs-rag.js'; */ export class PRAnalyzerAgent extends BasePRAgentWorkflow { constructor(options = {}) { - const model = ProviderFactory.createChatModel({ - provider: options.provider || 'anthropic', - apiKey: options.apiKey, - model: options.model, - temperature: options.temperature ?? 0.2, - maxTokens: options.maxTokens ?? 4000, - }); - super(model); + // Determine execution mode + const mode = options.mode || ExecutionMode.EXECUTE; + let model; + // Only create model in EXECUTE mode + if (mode === ExecutionMode.EXECUTE) { + // If a pre-configured BaseChatModel is passed (MCP case), use it directly + if (options.chatModel) { + model = options.chatModel; + } + else { + // Otherwise create model via ProviderFactory (CLI/Action case - backward compatible) + model = ProviderFactory.createChatModel({ + provider: options.provider || 'anthropic', + apiKey: options.apiKey, + model: options.model, + temperature: options.temperature ?? 0.2, + maxTokens: options.maxTokens ?? 50000, + }); + } + } + super(mode, model); } /** * Get agent metadata @@ -40,6 +54,7 @@ export class PRAnalyzerAgent extends BasePRAgentWorkflow { } /** * Analyze a PR with full agent workflow + * Returns either executed results (EXECUTE mode) or prompts (PROMPT_ONLY mode) */ async analyze(diff, title, mode, options) { // Parse diff into files @@ -59,6 +74,11 @@ export class PRAnalyzerAgent extends BasePRAgentWorkflow { maxCost: 5.0, mode: mode || { summary: true, risks: true, complexity: true }, archDocs: archDocsContext, + config: { + repoPath: options?.repoPath, + repoOwner: options?.repoOwner, + repoName: options?.repoName, + }, language: options?.language, framework: options?.framework, enableStaticAnalysis: options?.enableStaticAnalysis !== false, // Default to true diff --git a/dist/agents/pr-analyzer-agent.js.map b/dist/agents/pr-analyzer-agent.js.map index 1130805..91bfa0c 100644 --- a/dist/agents/pr-analyzer-agent.js.map +++ b/dist/agents/pr-analyzer-agent.js.map @@ -1 +1 @@ -{"version":3,"file":"pr-analyzer-agent.js","sourceRoot":"","sources":["../../src/agents/pr-analyzer-agent.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"pr-analyzer-agent.js","sourceRoot":"","sources":["../../src/agents/pr-analyzer-agent.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/analyzer.d.ts b/dist/analyzer.d.ts deleted file mode 100644 index 12c81c6..0000000 --- a/dist/analyzer.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AIProviderConfig, AnalysisResponse, AIProviderType } from './providers/types'; -import { PRAnalyzerConfig, ExtendedAnalysisResult } from './types'; -export declare function analyzeWithClaude(diff: string, title?: string, apiKey?: string): Promise; -/** - * Analyze PR with configurable provider - */ -export declare function analyzePR(diff: string, title?: string, config?: AIProviderConfig, repository?: string, prNumber?: number): Promise; -/** - * Analyze PR using configuration file - */ -export declare function analyzePRWithConfig(diff: string, title?: string, prConfig?: PRAnalyzerConfig, repository?: string, prNumber?: number, fallbackProviders?: AIProviderType[]): Promise; -/** - * Get available providers - */ -export { getAvailableProviders, isProviderAvailable } from './providers/factory'; diff --git a/dist/analyzer.js b/dist/analyzer.js deleted file mode 100644 index 178652d..0000000 --- a/dist/analyzer.js +++ /dev/null @@ -1,143 +0,0 @@ -"use strict"; -// Multi-Provider AI Analyzer -// Refactored to support multiple AI providers through factory pattern -Object.defineProperty(exports, "__esModule", { value: true }); -exports.isProviderAvailable = exports.getAvailableProviders = void 0; -exports.analyzeWithClaude = analyzeWithClaude; -exports.analyzePR = analyzePR; -exports.analyzePRWithConfig = analyzePRWithConfig; -const factory_1 = require("./providers/factory"); -// Legacy function for backward compatibility -async function analyzeWithClaude(diff, title, apiKey) { - const config = { - provider: 'claude', - model: 'claude-sonnet-4-5-20250929', - maxTokens: 1500, - temperature: 0.2, - apiKey: apiKey - }; - try { - const provider = (0, factory_1.createProvider)(config); - const request = { diff, title }; - const response = await provider.analyze(request); - return formatAnalysisResponse(response); - } - catch (error) { - console.error('Claude analysis failed:', error); - throw new Error('Sorry, AI analysis is temporarily unavailable.'); - } -} -/** - * Analyze PR with configurable provider - */ -async function analyzePR(diff, title, config, repository, prNumber) { - // Validate input - if (!diff || typeof diff !== 'string') { - throw new Error('Diff must be a non-empty string'); - } - if (!config) { - // Default to Claude if no config provided - config = { - provider: 'claude', - model: 'claude-sonnet-4-5-20250929', - maxTokens: 1500, - temperature: 0.2 - }; - } - const provider = (0, factory_1.createProvider)(config); - const request = { - diff, - title, - repository, - prNumber - }; - return await provider.analyze(request); -} -/** - * Analyze PR using configuration file - */ -async function analyzePRWithConfig(diff, title, prConfig, repository, prNumber, fallbackProviders) { - // Validate input - if (!diff || typeof diff !== 'string') { - throw new Error('Diff must be a non-empty string'); - } - if (!prConfig) { - // Use default configuration - const response = await analyzePR(diff, title, undefined, repository, prNumber); - return { - ...response, - provider: response.provider, - model: response.model - }; - } - const providersToTry = [ - prConfig.ai.provider, - ...(fallbackProviders || prConfig.ai.fallbackProviders || []) - ]; - // Remove duplicates - const uniqueProviders = Array.from(new Set(providersToTry)); - if (uniqueProviders.length === 0) { - throw new Error('No providers configured'); - } - let lastError = null; - const failedProviders = []; - for (const providerType of uniqueProviders) { - try { - console.info(`Attempting analysis with provider: ${providerType}`); - const provider = (0, factory_1.createProviderFromConfig)(prConfig, providerType); - const request = { - diff, - title, - repository, - prNumber - }; - const response = await provider.analyze(request); - console.info(`Successfully analyzed with ${providerType}`); - return { - ...response, - provider: response.provider, - model: response.model, - tokensUsed: response.tokensUsed, - recommendations: response.recommendations - }; - } - catch (error) { - failedProviders.push(providerType); - console.warn(`Provider ${providerType} failed:`, error); - lastError = error; - continue; - } - } - throw new Error(`All providers failed (${failedProviders.join(', ')}). Last error: ${lastError?.message}`); -} -/** - * Format analysis response for backward compatibility - */ -function formatAnalysisResponse(response) { - let formatted = `### Summary\n${response.summary}\n\n`; - if (response.risks.length > 0) { - formatted += `### Potential Risks\n`; - response.risks.forEach(risk => { - formatted += `- ${risk}\n`; - }); - formatted += '\n'; - } - else { - formatted += `### Potential Risks\nNone\n\n`; - } - formatted += `### Complexity: ${response.complexity}/5\n`; - if (response.recommendations && response.recommendations.length > 0) { - formatted += `\n### Recommendations\n`; - response.recommendations.forEach(rec => { - formatted += `- ${rec}\n`; - }); - } - return formatted; -} -/** - * Get available providers - */ -var factory_2 = require("./providers/factory"); -Object.defineProperty(exports, "getAvailableProviders", { enumerable: true, get: function () { return factory_2.getAvailableProviders; } }); -Object.defineProperty(exports, "isProviderAvailable", { enumerable: true, get: function () { return factory_2.isProviderAvailable; } }); -//# sourceMappingURL=analyzer.js.map \ No newline at end of file diff --git a/dist/analyzer.js.map b/dist/analyzer.js.map deleted file mode 100644 index fe50dbe..0000000 --- a/dist/analyzer.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/cli.d.ts b/dist/cli.d.ts deleted file mode 100644 index b798801..0000000 --- a/dist/cli.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/dist/cli.js b/dist/cli.js deleted file mode 100644 index 8cb36df..0000000 --- a/dist/cli.js +++ /dev/null @@ -1,442 +0,0 @@ -#!/usr/bin/env node -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const child_process_1 = require("child_process"); -const fs_1 = require("fs"); -const chalk_1 = __importDefault(require("chalk")); -const analyzer_1 = require("./analyzer"); -const pr_agent_1 = require("./pr-agent"); -const apiKey = process.env.ANTHROPIC_API_KEY; -async function getPRTitle() { - try { - const title = (0, child_process_1.execSync)('git log -1 --pretty=%B', { encoding: 'utf-8' }).trim(); - return title; - } - catch (error) { - return undefined; - } -} -function parseArgs() { - const args = process.argv.slice(2); - let diff; - let prTitle; - let diffCommand; - let useAgent = false; - const mode = { summary: false, risks: false, complexity: false }; - for (let i = 0; i < args.length; i++) { - const arg = args[i]; - switch (arg) { - case '--analyze': - if (i + 1 < args.length) { - const command = args[i + 1]; - i++; // consume next arg - switch (command) { - case '--summary': - mode.summary = true; - break; - case '--risks': - mode.risks = true; - break; - case '--complexity': - mode.complexity = true; - break; - case '--full': - mode.summary = true; - mode.risks = true; - mode.complexity = true; - break; - default: - console.error(chalk_1.default.red.bold(`❌ Unknown command: ${command}`)); - process.exit(1); - } - } - break; - case '--diff': - if (i + 1 < args.length) { - diff = args[++i]; - } - break; - case '--title': - if (i + 1 < args.length) { - prTitle = args[++i]; - } - break; - case '--file': - if (i + 1 < args.length) { - const filePath = args[++i]; - diff = (0, fs_1.readFileSync)(filePath, 'utf-8'); - } - break; - case '--staged': - diffCommand = 'staged'; - break; - case '--branch': - if (i + 1 < args.length) { - const branch = args[++i]; - diffCommand = branch; - } - break; - case '--agent': - useAgent = true; - break; - } - } - // If no mode specified, default to full - if (!mode.summary && !mode.risks && !mode.complexity) { - mode.summary = true; - mode.risks = true; - mode.complexity = true; - } - return { diff, mode, prTitle, diffCommand, useAgent }; -} -function shouldSkipFile(filePath) { - // Skip dist files and other build artifacts - if (filePath.startsWith('dist/') || filePath.includes('/dist/')) { - return true; - } - if (filePath.startsWith('node_modules/') || filePath.includes('/node_modules/')) { - return true; - } - // Skip .map files in dist - if (filePath.endsWith('.map') && filePath.includes('dist/')) { - return true; - } - // Skip .d.ts files in dist - if (filePath.includes('.d.ts') && filePath.includes('dist/')) { - return true; - } - return false; -} -async function getUntrackedFiles() { - try { - const output = (0, child_process_1.execSync)('git ls-files --others --exclude-standard', { - encoding: 'utf-8', - maxBuffer: 10 * 1024 * 1024 - }); - return output.trim().split('\n').filter(f => f.length > 0 && !shouldSkipFile(f)); - } - catch (error) { - return []; - } -} -async function getGitDiffWithCommand(command) { - try { - let diff = ''; - const maxBuffer = 200 * 1024 * 1024; // 200MB - if (!command || command === 'origin/main') { - try { - diff = (0, child_process_1.execSync)('git diff origin/main', { - encoding: 'utf-8', - maxBuffer - }); - } - catch { - // Fallback to main branch - console.log(chalk_1.default.yellow('⚠️ origin/main not found, trying main branch...')); - diff = (0, child_process_1.execSync)('git diff main', { - encoding: 'utf-8', - maxBuffer - }); - } - } - else if (command === 'staged') { - diff = (0, child_process_1.execSync)('git diff --staged', { - encoding: 'utf-8', - maxBuffer - }); - } - else { - // Custom branch or reference - diff = (0, child_process_1.execSync)(`git diff ${command}`, { - encoding: 'utf-8', - maxBuffer - }); - } - // Normalize diff (remove trailing whitespace but preserve structure) - diff = diff.trim(); - // Filter out dist files from the diff itself - const lines = diff.split('\n'); - const filteredLines = []; - let i = 0; - while (i < lines.length) { - const line = lines[i]; - if (line.startsWith('diff --git')) { - const match = line.match(/^diff --git a\/(.+?) b\/(.+?)$/); - if (match) { - const filePath = match[2] !== '/dev/null' ? match[2] : match[1]; - if (shouldSkipFile(filePath)) { - // Skip this entire file block - jump to next diff --git line - i++; - while (i < lines.length && !lines[i].startsWith('diff --git')) { - i++; - } - continue; // Skip adding this block - } - } - } - filteredLines.push(line); - i++; - } - diff = filteredLines.join('\n').trim(); - // Also get untracked files and add them as new files in the diff format - const untrackedFiles = await getUntrackedFiles(); - if (untrackedFiles.length > 0) { - const fs = require('fs'); - for (const filePath of untrackedFiles) { - if (shouldSkipFile(filePath)) - continue; - try { - // Skip binary files and very large files (>5MB) - if (!fs.existsSync(filePath)) - continue; - const stats = fs.statSync(filePath); - if (stats.size > 5 * 1024 * 1024) - continue; - // Try to read as text (will throw for binary files) - const content = fs.readFileSync(filePath, 'utf-8'); - const lines = content.split('\n'); - // Format as git diff for new file (proper git diff format) - const diffHeader = `diff --git a/dev/null b/${filePath}\nnew file mode 100644\nindex 0000000..1111111\n--- /dev/null\n+++ b/${filePath}\n@@ -0,0 +1,${lines.length} @@\n`; - // Add content with + prefix (git diff format) - let fileDiff = diffHeader; - for (const line of lines) { - fileDiff += `+${line}\n`; - } - diff += (diff ? '\n' : '') + fileDiff; - } - catch (err) { - // Skip files that can't be read as text (binary, permissions, etc.) - // Optionally add a binary file marker - try { - if (fs.existsSync(filePath)) { - const stats = fs.statSync(filePath); - // Add binary file indicator - diff += (diff ? '\n' : '') + `diff --git a/dev/null b/${filePath}\nnew file mode 100644\nBinary file (${(stats.size / 1024).toFixed(0)}KB)\n`; - } - } - catch (statErr) { - // Skip this file - continue; - } - } - } - } - // If diff is empty, check if we have untracked files - if (!diff.trim() && untrackedFiles.length === 0) { - throw new Error('No changes detected'); - } - return diff || ''; - } - catch (error) { - console.error(chalk_1.default.red.bold('❌ Error getting git diff:'), error); - console.error(chalk_1.default.yellow('💡 Make sure you have a git repository with changes to analyze.')); - process.exit(1); - } -} -function estimateDiffSize(diff) { - // Rough estimate: 1 character ≈ 0.25 tokens - return Math.ceil(diff.length / 4); -} -async function main() { - // Show welcome banner - console.log(chalk_1.default.cyan.bold('\n🤖 PR Agent - AI Code Analyzer\n')); - if (!apiKey) { - console.error(chalk_1.default.red.bold('❌ Error: ANTHROPIC_API_KEY environment variable is not set')); - console.error(chalk_1.default.yellow('💡 Please set it with: export ANTHROPIC_API_KEY="your-api-key"')); - process.exit(1); - } - const { diff, mode, prTitle, diffCommand, useAgent } = parseArgs(); - // Get the diff - let finalDiff; - console.log(chalk_1.default.blue('📥 Fetching diff...')); - if (diff) { - finalDiff = diff; - } - else if (diffCommand) { - finalDiff = await getGitDiffWithCommand(diffCommand); - } - else { - finalDiff = await getGitDiffWithCommand(); - } - const finalTitle = prTitle || await getPRTitle(); - if (!finalDiff) { - console.error(chalk_1.default.red.bold('❌ Error: No diff found')); - process.exit(1); - } - // Estimate token count - const estimatedTokens = estimateDiffSize(finalDiff); - console.log(chalk_1.default.green(`✅ Diff ready: ~${estimatedTokens.toLocaleString()} tokens (${(finalDiff.length / 1024).toFixed(0)}KB)`)); - if (useAgent || finalDiff.length > 50000) { - // Use intelligent agent for large diffs or if explicitly requested - console.log(chalk_1.default.magenta.bold('\n🤖 Using Intelligent Agent Analysis (handling large diffs without chunking)...\n')); - console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')); - try { - const agentConfig = { - provider: 'claude', - model: 'claude-sonnet-4-5-20250929', - maxTokens: 2000, - temperature: 0.2, - apiKey: apiKey - }; - const agent = new pr_agent_1.PRAnalysisAgent(agentConfig, apiKey); - const result = await agent.analyze(finalDiff, finalTitle, mode, 'terminal'); - // Display results based on mode - console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk_1.default.green.bold('\n✨ Agent Analysis Complete!\n')); - // Clean summary - remove markdown headers and duplicates - let cleanSummary = result.summary; - // Remove markdown headers from summary - cleanSummary = cleanSummary.replace(/^#+\s*PR Analysis:?\s*/im, ''); - cleanSummary = cleanSummary.replace(/^##\s*Summary\s*/im, ''); - cleanSummary = cleanSummary.trim(); - if (mode.summary) { - console.log(chalk_1.default.cyan.bold('📋 Overall Summary\n')); - console.log(chalk_1.default.white(cleanSummary)); - console.log('\n'); - } - // Group risks by file for better organization - if (mode.risks && result.fileAnalyses.size > 0) { - const fileEntries = Array.from(result.fileAnalyses.entries()); - const filesWithRisks = fileEntries.filter(([_, analysis]) => analysis.risks.length > 0); - if (filesWithRisks.length > 0) { - console.log(chalk_1.default.yellow.bold(`⚠️ Risks by File (${filesWithRisks.length} files with risks)\n`)); - filesWithRisks.forEach(([path, analysis]) => { - console.log(chalk_1.default.cyan(` ${path}`)); - analysis.risks.forEach((risk, i) => { - // Extract file reference from risk if present, otherwise use current file - const cleanRisk = risk.replace(/^\[File: [^\]]+\]\s*/, ''); - console.log(chalk_1.default.white(` ${i + 1}. ${cleanRisk}`)); - }); - console.log(''); - }); - } - else if (result.overallRisks.length > 0) { - // Fallback to overall risks if no file-level risks - console.log(chalk_1.default.yellow.bold('⚠️ Overall Risks\n')); - result.overallRisks.forEach((risk, i) => { - console.log(chalk_1.default.white(` ${i + 1}. ${risk}`)); - }); - console.log('\n'); - } - else { - console.log(chalk_1.default.yellow.bold('⚠️ Risks\n')); - console.log(chalk_1.default.white(' None identified\n\n')); - } - } - if (mode.complexity) { - console.log(chalk_1.default.magenta.bold(`📊 Overall Complexity: ${result.overallComplexity}/5\n`)); - } - // Show file-level complexity summary if requested - if ((mode.summary || mode.complexity) && result.fileAnalyses.size > 0) { - console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk_1.default.cyan.bold(`\n📁 File Analysis (${result.fileAnalyses.size} files)\n`)); - const fileEntries = Array.from(result.fileAnalyses.entries()); - const highComplexity = fileEntries.filter(([_, analysis]) => analysis.complexity >= 4); - const mediumComplexity = fileEntries.filter(([_, analysis]) => analysis.complexity === 3); - if (highComplexity.length > 0) { - console.log(chalk_1.default.red.bold('🔴 High Complexity:\n')); - highComplexity.forEach(([path, analysis]) => { - console.log(chalk_1.default.white(` • ${path} (${analysis.complexity}/5)`)); - if (mode.risks && analysis.risks.length > 0) { - console.log(chalk_1.default.gray(` ${analysis.risks.length} risk${analysis.risks.length > 1 ? 's' : ''} found`)); - } - }); - console.log(''); - } - if (mediumComplexity.length > 0 && mediumComplexity.length <= 10) { - console.log(chalk_1.default.yellow.bold('🟡 Medium Complexity:\n')); - mediumComplexity.slice(0, 5).forEach(([path, analysis]) => { - console.log(chalk_1.default.white(` • ${path} (${analysis.complexity}/5)`)); - }); - if (mediumComplexity.length > 5) { - console.log(chalk_1.default.gray(` ... and ${mediumComplexity.length - 5} more`)); - } - console.log(''); - } - } - // Show recommendations if available - if (result.recommendations.length > 0) { - console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk_1.default.cyan.bold('\n💡 Recommendations\n')); - result.recommendations.forEach((rec, i) => { - console.log(chalk_1.default.white(` ${i + 1}. ${rec}`)); - }); - console.log('\n'); - } - // Show agent reasoning if available (minimal) - if (result.reasoning.length > 0 && result.reasoning.length <= 5) { - console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk_1.default.cyan.bold('\n🤔 Analysis Strategy\n')); - result.reasoning.forEach((reason, i) => { - // Extract just the strategy summary, not all iterations - if (reason.includes('Strategy:') || i === 0) { - console.log(chalk_1.default.gray(` ${reason.substring(0, 150)}${reason.length > 150 ? '...' : ''}`)); - } - }); - console.log('\n'); - } - if (result.totalTokensUsed) { - console.log(chalk_1.default.gray(`\nTotal tokens used: ${result.totalTokensUsed.toLocaleString()}`)); - } - console.log(chalk_1.default.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')); - } - catch (error) { - console.error(chalk_1.default.red.bold('\n❌ Agent analysis failed:'), error.message); - if (error.stack) { - console.error(chalk_1.default.gray(error.stack)); - } - process.exit(1); - } - } - else { - // Use traditional analysis for small diffs - console.log(chalk_1.default.magenta.bold('\n🔍 Analyzing code with Claude AI...\n')); - console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')); - try { - const analysis = await (0, analyzer_1.analyzeWithClaude)(finalDiff, finalTitle, apiKey); - console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk_1.default.green.bold('\n✨ Analysis Complete!\n')); - // Filter output based on mode - const lines = analysis.split('\n'); - let output = ''; - let currentSection = ''; - for (const line of lines) { - if (line.startsWith('### Summary') && mode.summary) { - currentSection = 'summary'; - output += line + '\n'; - } - else if (line.startsWith('### Potential Risks') && mode.risks) { - currentSection = 'risks'; - output += line + '\n'; - } - else if (line.startsWith('### Complexity') && mode.complexity) { - currentSection = 'complexity'; - output += line + '\n'; - } - else if (line.startsWith('###')) { - currentSection = ''; - } - else if (currentSection && (currentSection === 'summary' || currentSection === 'risks' || currentSection === 'complexity')) { - output += line + '\n'; - } - } - console.log(chalk_1.default.white(output.trim())); - console.log(chalk_1.default.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')); - } - catch (error) { - if (error.message && error.message.includes('rate-limits')) { - console.error(chalk_1.default.red.bold('\n❌ Rate limit error: Your diff is too large for the API.')); - console.error(chalk_1.default.yellow('\n💡 Try using --agent flag for intelligent analysis of large diffs')); - } - else { - console.error(chalk_1.default.red.bold('\n❌ Error during analysis:'), error); - } - process.exit(1); - } - } -} -main(); -//# sourceMappingURL=cli.js.map \ No newline at end of file diff --git a/dist/cli.js.map b/dist/cli.js.map deleted file mode 100644 index d205ef4..0000000 --- a/dist/cli.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/cli/commands/analyze.command.d.ts b/dist/cli/commands/analyze.command.d.ts index d18214c..8622555 100644 --- a/dist/cli/commands/analyze.command.d.ts +++ b/dist/cli/commands/analyze.command.d.ts @@ -14,6 +14,11 @@ interface AnalyzeOptions { verbose?: boolean; maxCost?: number; archDocs?: boolean; + peerReview?: boolean; + showClassification?: boolean; + scanCoverage?: boolean; + showCoverage?: boolean; + showStaticAnalysis?: boolean; } /** * Analyze command - analyze PR diffs with AI diff --git a/dist/cli/commands/analyze.command.js b/dist/cli/commands/analyze.command.js index 364a862..399b346 100644 --- a/dist/cli/commands/analyze.command.js +++ b/dist/cli/commands/analyze.command.js @@ -2,11 +2,17 @@ import * as fs from 'fs'; import { execSync } from 'child_process'; import chalk from 'chalk'; import ora from 'ora'; +import open from 'open'; import { PRAnalyzerAgent } from '../../agents/pr-analyzer-agent.js'; import { loadUserConfig, getApiKey } from '../utils/config-loader.js'; import { archDocsExists } from '../../utils/arch-docs-parser.js'; import { resolveDefaultBranch } from '../../utils/branch-resolver.js'; import { ConfigurationError, GitHubAPIError, GitError } from '../../utils/errors.js'; +import { createPeerReviewIntegration, formatPeerReviewOutput, PeerReviewMode, } from '../../issue-tracker/index.js'; +import { ExecutionMode } from '../../types/agent.types.js'; +import { ProviderFactory } from '../../providers/index.js'; +import { saveAnalysis } from '../../db/index.js'; +import { getCoverageAnalysis, formatCoverageAnalysis, runEslintAnalysis, formatStaticAnalysis } from '../../tools/index.js'; /** * Determine which files should be skipped during analysis */ @@ -180,6 +186,60 @@ async function getPRTitle() { return undefined; } } +/** + * Get repository info from git remote URL + */ +function getRepoInfo() { + try { + const remoteUrl = execSync('git remote get-url origin', { encoding: 'utf-8' }).trim(); + // Handle SSH format: git@github.com:owner/repo.git + // Handle HTTPS format: https://github.com/owner/repo.git + const sshMatch = remoteUrl.match(/git@[^:]+:([^/]+)\/(.+?)(?:\.git)?$/); + if (sshMatch) { + return { owner: sshMatch[1], name: sshMatch[2] }; + } + const httpsMatch = remoteUrl.match(/https?:\/\/[^/]+\/([^/]+)\/(.+?)(?:\.git)?$/); + if (httpsMatch) { + return { owner: httpsMatch[1], name: httpsMatch[2] }; + } + // Fallback to current directory name + return { owner: 'local', name: process.cwd().split(/[\\/]/).pop() || 'unknown' }; + } + catch { + return { owner: 'local', name: process.cwd().split(/[\\/]/).pop() || 'unknown' }; + } +} +/** + * Get git author from config + */ +function getGitAuthor() { + try { + return execSync('git config user.name', { encoding: 'utf-8' }).trim() || 'unknown'; + } + catch { + return 'unknown'; + } +} +/** + * Extract PR number from branch name if it follows common patterns + * e.g., feature/PR-123, fix-123, 123-feature + */ +function extractPRNumber(branchName, title) { + // Try to extract from branch name + if (branchName) { + const branchMatch = branchName.match(/(?:PR-?|#)?(\d+)/i); + if (branchMatch) + return parseInt(branchMatch[1], 10); + } + // Try to extract from title + if (title) { + const titleMatch = title.match(/#(\d+)/); + if (titleMatch) + return parseInt(titleMatch[1], 10); + } + // Generate a timestamp-based "PR number" for local analysis + return Math.floor(Date.now() / 1000) % 100000; +} /** * Estimate diff size in tokens */ @@ -232,6 +292,7 @@ export async function analyzePR(options = {}) { } const provider = (options.provider || config.ai?.provider || 'anthropic').toLowerCase(); const apiKey = getApiKey(provider, config); + const model = options.model || config.ai?.model; if (!apiKey) { spinner.fail('No API key found'); console.error(chalk.yellow('💡 Please set it in one of these ways:')); @@ -240,6 +301,10 @@ export async function analyzePR(options = {}) { console.error(chalk.gray(' - Anthropic (Claude): export ANTHROPIC_API_KEY="your-api-key"')); console.error(chalk.gray(' - OpenAI (GPT): export OPENAI_API_KEY="your-api-key"')); console.error(chalk.gray(' - Google (Gemini): export GOOGLE_API_KEY="your-api-key"')); + console.error(chalk.gray(' - Zhipu (GLM): export ZHIPU_API_KEY="your-api-key"')); + if (options.verbose) { + console.error(chalk.gray(` Debug: Provider=${provider}, Config apiKeys=${JSON.stringify(config.apiKeys || {})}`)); + } process.exit(1); } spinner.succeed(`Using AI provider: ${provider}`); @@ -345,21 +410,214 @@ export async function analyzePR(options = {}) { else if (options.archDocs && !hasArchDocs) { console.log(chalk.yellow('⚠️ --arch-docs flag specified but no .arch-docs folder found\n')); } - const model = options.model || config.ai?.model; + // Get repo info early so we can pass it to the agent for caching + const repoInfo = getRepoInfo(); const agent = new PRAnalyzerAgent({ + mode: ExecutionMode.EXECUTE, // CLI always executes with API key provider: provider, apiKey, model, }); - const result = await agent.analyze(diff, title, mode, { + const analysisResult = await agent.analyze(diff, title, mode, { useArchDocs: useArchDocs && hasArchDocs, repoPath: process.cwd(), + repoOwner: repoInfo.owner, + repoName: repoInfo.name, language: config.analysis?.language, framework: config.analysis?.framework, enableStaticAnalysis: config.analysis?.enableStaticAnalysis !== false, }); + // Type guard: CLI always uses EXECUTE mode, so result is always AgentResult + if (analysisResult.mode === 'prompt_only') { + throw new Error('Unexpected prompt-only result in CLI EXECUTE mode'); + } + const result = analysisResult; // Display results - displayAgentResults(result, mode, options.verbose || false); + displayAgentResults(result, mode, options.verbose || false, options.showClassification || false); + // Run and display coverage analysis if requested + if (options.scanCoverage || options.showCoverage) { + console.log(chalk.gray('\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + const coverageAnalysis = getCoverageAnalysis(process.cwd()); + if (coverageAnalysis.hasReport) { + console.log('\\n' + formatCoverageAnalysis(coverageAnalysis)); + } + else { + console.log(chalk.yellow('\\n📊 No coverage report found.')); + console.log(chalk.gray(' Run: npm test -- --coverage to generate one.')); + } + } + // Run and display ESLint static analysis if requested + if (options.showStaticAnalysis) { + console.log(chalk.gray('\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.cyan('\\n🔬 Running static analysis...')); + const staticAnalysis = await runEslintAnalysis(process.cwd()); + console.log('\\n' + formatStaticAnalysis(staticAnalysis)); + } + // Save analysis results to local database for dashboard + try { + const repoInfo = getRepoInfo(); + const author = getGitAuthor(); + let branchName; + try { + branchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim(); + } + catch { + // ignore + } + const prNumber = extractPRNumber(branchName, title); + // Calculate overall complexity from file analyses + let overallComplexity = 1; + if (result.fileAnalyses && result.fileAnalyses.size > 0) { + const complexities = Array.from(result.fileAnalyses.values()).map((f) => f.complexity || 1); + overallComplexity = Math.round(complexities.reduce((a, b) => a + b, 0) / complexities.length); + } + // Calculate DevOps cost if estimates available + const devOpsCostMonthly = result.devOpsCostEstimates?.reduce((sum, e) => sum + (e.estimatedNewCost || 0), 0) || 0; + const devOpsResources = result.devOpsCostEstimates + ? JSON.stringify(result.devOpsCostEstimates) + : undefined; + saveAnalysis({ + pr_number: prNumber, + repo_owner: repoInfo.owner, + repo_name: repoInfo.name, + author: author, + title: title || 'Untitled Analysis', + complexity: overallComplexity, + risks_count: result.fixes?.filter((f) => f.severity === 'critical' || f.severity === 'warning').length || 0, + risks: JSON.stringify(result.fixes?.filter((f) => f.severity === 'critical' || f.severity === 'warning').map((f) => f.comment) || []), + recommendations: JSON.stringify(result.recommendations || []), + // DevOps/Infrastructure cost tracking (v0.2.0) + devops_cost_monthly: devOpsCostMonthly > 0 ? devOpsCostMonthly : undefined, + devops_resources: devOpsResources, + has_test_suggestions: (result.testSuggestions?.length ?? 0) > 0 ? 1 : 0, + test_suggestions_count: result.testSuggestions?.length ?? 0, + coverage_percentage: result.coverageReport?.overallPercentage, + // Project classification cache (v0.3.0) + project_classification: result.projectClassification, + }); + if (options.verbose) { + console.log(chalk.gray(` Analysis saved to local database (PR #${prNumber})`)); + } + } + catch (saveError) { + if (options.verbose) { + console.log(chalk.yellow(` Warning: Could not save to local database: ${saveError.message}`)); + } + } + // Run Peer Review if enabled (via flag or config) + const peerReviewEnabled = options.peerReview ?? config.peerReview?.enabled ?? false; + if (options.verbose) { + console.log(chalk.gray(`\n Debug: peerReviewEnabled=${peerReviewEnabled}, options.peerReview=${options.peerReview}, config.peerReview?.enabled=${config.peerReview?.enabled}`)); + } + if (peerReviewEnabled) { + // Pass the same provider config to peer review so it uses the same LLM + const peerReviewResult = await runPeerReview(config, diff, title, result, options.verbose || false, { + provider, + apiKey, + model, + }); + // Save peer review results to database for dashboard + if (peerReviewResult && peerReviewResult.enabled && peerReviewResult.analysis) { + try { + const repoInfo = getRepoInfo(); + const author = getGitAuthor(); + let branchName; + try { + branchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim(); + } + catch { + // ignore + } + const prNumber = extractPRNumber(branchName, title); + // Calculate overall complexity from file analyses + let overallComplexity = 1; + if (result.fileAnalyses && result.fileAnalyses.size > 0) { + const complexities = Array.from(result.fileAnalyses.values()).map((f) => f.complexity || 1); + overallComplexity = Math.round(complexities.reduce((a, b) => a + b, 0) / complexities.length); + } + // Calculate DevOps cost if estimates available + const devOpsCostMonthly = result.devOpsCostEstimates?.reduce((sum, e) => sum + (e.estimatedNewCost || 0), 0) || 0; + const devOpsResources = result.devOpsCostEstimates + ? JSON.stringify(result.devOpsCostEstimates) + : undefined; + // Extract peer review data + const analysis = peerReviewResult.analysis; + const primaryTicket = peerReviewResult.primaryTicket; + // Determine verdict from peerReview analysis + let verdict = 'needs_discussion'; + if (analysis.peerReview.readyForReview && analysis.peerReview.blockers.length === 0) { + verdict = 'approve'; + } + else if (analysis.peerReview.blockers.length > 0) { + verdict = 'request_changes'; + } + saveAnalysis({ + pr_number: prNumber, + repo_owner: repoInfo.owner, + repo_name: repoInfo.name, + author: author, + title: title || 'Untitled Analysis', + complexity: overallComplexity, + risks_count: result.fixes?.filter((f) => f.severity === 'critical' || f.severity === 'warning').length || 0, + risks: JSON.stringify(result.fixes?.filter((f) => f.severity === 'critical' || f.severity === 'warning').map((f) => f.comment) || []), + recommendations: JSON.stringify(result.recommendations || []), + // DevOps/Infrastructure cost tracking (v0.2.0) + devops_cost_monthly: devOpsCostMonthly > 0 ? devOpsCostMonthly : undefined, + devops_resources: devOpsResources, + has_test_suggestions: (result.testSuggestions?.length ?? 0) > 0 ? 1 : 0, + test_suggestions_count: result.testSuggestions?.length ?? 0, + coverage_percentage: result.coverageReport?.overallPercentage, + // Peer Review data (v0.3.0) + peer_review_enabled: 1, + ticket_key: primaryTicket?.key, + ticket_quality_score: analysis.ticketQuality.overallScore, + ticket_quality_tier: analysis.ticketQuality.tier, + ac_compliance_percentage: analysis.acValidation?.compliancePercentage, + ac_requirements_met: analysis.acValidation?.criteriaAnalysis?.filter(c => c.status === 'met').length, + ac_requirements_total: analysis.acValidation?.criteriaAnalysis?.length, + peer_review_verdict: verdict, + peer_review_blockers: JSON.stringify(analysis.peerReview.blockers), + peer_review_warnings: JSON.stringify(analysis.peerReview.warnings), + implementation_completeness: analysis.peerReview.implementationCompleteness, + quality_score: analysis.peerReview.qualityScore, + }); + if (options.verbose) { + console.log(chalk.gray(` Peer review results saved to database (PR #${prNumber}, ticket: ${primaryTicket?.key || 'N/A'})`)); + } + } + catch (saveError) { + if (options.verbose) { + console.log(chalk.yellow(` Warning: Could not save peer review to database: ${saveError.message}`)); + } + } + } + } + // Auto-start and open dashboard after analysis completes + try { + const dashboardUrl = 'http://localhost:3000'; + console.log(chalk.gray(`\n📊 Starting dashboard...`)); + // Start dashboard server in background + const { spawn } = await import('child_process'); + const dashboardProcess = spawn(process.execPath, [ + process.argv[1], // Path to CLI entry point + 'dashboard' + ], { + detached: true, + stdio: 'ignore' + }); + dashboardProcess.unref(); + // Wait a moment for server to start + await new Promise(resolve => setTimeout(resolve, 2000)); + console.log(chalk.green(`✓ Dashboard running at ${dashboardUrl}`)); + console.log(chalk.gray(` Opening browser...`)); + await open(dashboardUrl); + } + catch (openError) { + if (options.verbose) { + console.log(chalk.yellow(` Could not start dashboard automatically: ${openError.message}`)); + } + console.log(chalk.gray(` Start manually with: pr-agent dashboard`)); + } } catch (error) { spinner.fail('Analysis failed'); @@ -405,7 +663,7 @@ export async function analyzePR(options = {}) { /** * Display agent analysis results */ -function displayAgentResults(result, mode, verbose) { +function displayAgentResults(result, mode, verbose, showClassification = false) { console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); console.log(chalk.green.bold('\n✨ Agent Analysis Complete!\n')); // Clean summary - remove markdown headers and duplicates @@ -421,6 +679,11 @@ function displayAgentResults(result, mode, verbose) { console.log(chalk.white(cleanSummary)); console.log('\n'); } + // Display project classification only if explicitly requested + if (showClassification && result.projectClassification) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(result.projectClassification); + } // Combined quick actions section - only fixes with line numbers (for PR comments) // Filter: only critical/warning, must have line number, sort critical first const prCommentFixes = result.fixes @@ -490,6 +753,52 @@ function displayAgentResults(result, mode, verbose) { console.log(chalk.gray(` ... and ${totalFilteredFixes - prCommentFixes.length} more issues\n`)); } } + // Show recommendations if available + if (result.recommendations.length > 0) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.cyan.bold('\n💡 Recommendations\n')); + result.recommendations.forEach((rec, i) => { + console.log(chalk.white(` ${i + 1}. ${rec}`)); + }); + console.log('\n'); + } + // Show agent reasoning if available (minimal) + if (verbose && result.reasoning.length > 0 && result.reasoning.length <= 5) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.cyan.bold('\n🤔 Analysis Strategy\n')); + result.reasoning.forEach((reason, i) => { + if (reason.includes('Strategy:') || i === 0) { + console.log(chalk.gray(` ${reason.substring(0, 150)}${reason.length > 150 ? '...' : ''}`)); + } + }); + console.log('\n'); + } + // Show arch-docs impact if used + if (result.archDocsImpact?.used) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.blue.bold('\n📚 Architecture Documentation Impact\n')); + console.log(chalk.white(`Documents analyzed: ${result.archDocsImpact.docsAvailable}`)); + console.log(chalk.white(`Relevant sections used: ${result.archDocsImpact.sectionsUsed}\n`)); + if (result.archDocsImpact.influencedStages.length > 0) { + console.log(chalk.cyan('Stages influenced by arch-docs:')); + result.archDocsImpact.influencedStages.forEach((stage) => { + const stageEmoji = stage === 'file-analysis' ? '🔍' : + stage === 'risk-detection' ? '⚠️' : + stage === 'complexity-calculation' ? '📊' : + stage === 'summary-generation' ? '📝' : + stage === 'refinement' ? '🔄' : '✨'; + console.log(chalk.white(` ${stageEmoji} ${stage}`)); + }); + console.log(''); + } + if (result.archDocsImpact.keyInsights.length > 0) { + console.log(chalk.cyan('Key insights from arch-docs integration:\n')); + result.archDocsImpact.keyInsights.forEach((insight, i) => { + console.log(chalk.white(` ${i + 1}. ${insight}`)); + }); + console.log(''); + } + } else { console.log(chalk.green.bold('✅ Status\n')); console.log(chalk.white(' No critical issues found.\n\n')); @@ -498,6 +807,211 @@ function displayAgentResults(result, mode, verbose) { if (result.totalTokensUsed) { console.log(chalk.gray(`Total tokens used: ${result.totalTokensUsed.toLocaleString()}`)); } + // Show test suggestions if available + if (result.testSuggestions && result.testSuggestions.length > 0) { + const newTests = result.testSuggestions.filter((s) => !s.isEnhancement); + const enhancements = result.testSuggestions.filter((s) => s.isEnhancement); + // Show new test suggestions + if (newTests.length > 0) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.yellow.bold(`\n🧪 Test Suggestions (${newTests.length} files need tests)\n`)); + for (const suggestion of newTests) { + console.log(chalk.cyan(` 📝 ${suggestion.forFile}`)); + console.log(chalk.gray(` Framework: ${suggestion.testFramework}`)); + if (suggestion.testFilePath) { + console.log(chalk.gray(` Suggested test file: ${suggestion.testFilePath}`)); + } + console.log(chalk.white(` ${suggestion.description}\n`)); + if (suggestion.testCode) { + console.log(chalk.gray(' ┌─────────────────────────────────────────')); + const codeLines = suggestion.testCode.split('\n').slice(0, 10); + codeLines.forEach((line) => { + console.log(chalk.gray(' │ ') + chalk.white(line)); + }); + if (suggestion.testCode.split('\n').length > 10) { + console.log(chalk.gray(' │ ... (copy full code below)')); + } + console.log(chalk.gray(' └─────────────────────────────────────────\n')); + } + } + } + // Show test enhancement suggestions + if (enhancements.length > 0) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.green.bold(`\n🔬 Test Enhancement Suggestions (${enhancements.length} test files can be improved)\n`)); + for (const suggestion of enhancements) { + console.log(chalk.cyan(` 📊 ${suggestion.existingTestFile || suggestion.testFilePath}`)); + console.log(chalk.gray(` Source: ${suggestion.forFile}`)); + console.log(chalk.white(` ${suggestion.description}\n`)); + if (suggestion.testCode && suggestion.testCode.trim()) { + console.log(chalk.gray(' ┌─────────────────────────────────────────')); + const codeLines = suggestion.testCode.split('\n').slice(0, 15); + codeLines.forEach((line) => { + console.log(chalk.gray(' │ ') + chalk.white(line)); + }); + if (suggestion.testCode.split('\n').length > 15) { + console.log(chalk.gray(' │ ... (more enhancements available)')); + } + console.log(chalk.gray(' └─────────────────────────────────────────\n')); + } + } + } + } + // Show coverage report if available + if (result.coverageReport && result.coverageReport.available) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.green.bold('\n📊 Test Coverage Report\n')); + const coverage = result.coverageReport; + if (coverage.overallPercentage !== undefined) { + const emoji = coverage.overallPercentage >= 80 ? '🟢' : coverage.overallPercentage >= 60 ? '🟡' : '🔴'; + console.log(chalk.white(` ${emoji} Overall Coverage: ${coverage.overallPercentage.toFixed(1)}%`)); + } + if (coverage.lineCoverage !== undefined) { + console.log(chalk.gray(` Lines: ${coverage.lineCoverage.toFixed(1)}%`)); + } + if (coverage.branchCoverage !== undefined) { + console.log(chalk.gray(` Branches: ${coverage.branchCoverage.toFixed(1)}%`)); + } + if (coverage.delta !== undefined) { + const deltaEmoji = coverage.delta >= 0 ? '📈' : '📉'; + const deltaColor = coverage.delta >= 0 ? chalk.green : chalk.red; + console.log(deltaColor(` ${deltaEmoji} Coverage Delta: ${coverage.delta >= 0 ? '+' : ''}${coverage.delta.toFixed(1)}%`)); + } + if (coverage.coverageTool) { + console.log(chalk.gray(`\n Tool: ${coverage.coverageTool}`)); + } + console.log(''); + } + // Show DevOps cost estimates if available + if (result.devOpsCostEstimates && result.devOpsCostEstimates.length > 0) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.yellow.bold('\n💰 AWS Infrastructure Cost Estimates\n')); + let totalCost = 0; + for (const estimate of result.devOpsCostEstimates) { + const emoji = estimate.confidence === 'high' ? '🟢' : estimate.confidence === 'medium' ? '🟡' : '🔴'; + console.log(chalk.white(` ${emoji} ${estimate.resourceType.toUpperCase()}: ~$${estimate.estimatedNewCost.toFixed(2)}/month`)); + if (estimate.details) { + console.log(chalk.gray(` ${estimate.details}`)); + } + totalCost += estimate.estimatedNewCost; + } + console.log(chalk.cyan.bold(`\n 📊 Total Estimated Impact: ~$${totalCost.toFixed(2)}/month`)); + console.log(chalk.gray('\n ⚠️ Estimates are approximate. Actual costs depend on usage and configuration.\n')); + } console.log(chalk.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')); } +/** + * Run Peer Review analysis against linked Jira tickets + * + * This extends the PR analysis with business context validation: + * - Fetches linked Jira tickets from PR title/branch + * - Rates ticket quality + * - Validates implementation against derived requirements + * - Provides senior-dev style verdict + */ +async function runPeerReview(config, diff, title, prAnalysisResult, verbose, providerOptions) { + const spinner = ora('Running Peer Review analysis...').start(); + try { + // Create LLM using the same provider as main analysis + const llm = ProviderFactory.createChatModel({ + provider: providerOptions.provider, + apiKey: providerOptions.apiKey, + model: providerOptions.model, + temperature: 0.2, + maxTokens: 50000, + }); + // Create peer review integration from config, passing the LLM in EXECUTE mode + const peerReviewConfig = config.peerReview || {}; + const integration = createPeerReviewIntegration(peerReviewConfig, PeerReviewMode.EXECUTE, llm); + if (!integration.isEnabled()) { + spinner.warn('Peer Review enabled but not configured. Add Jira settings to config.'); + console.log(chalk.gray(' Run: pr-agent config --set peerReview.instanceUrl=https://your.atlassian.net')); + console.log(chalk.gray(' Or configure MCP: peerReview.useMcp=true')); + if (verbose) { + console.log(chalk.gray(` Debug: peerReviewConfig=${JSON.stringify(peerReviewConfig)}`)); + } + return null; + } + // Get branch name for ticket extraction + let branchName; + try { + branchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim(); + } + catch { + // Ignore - branch name is optional + } + // Get commit messages for ticket extraction + let commitMessages = []; + try { + const commits = execSync('git log --oneline -10', { encoding: 'utf-8' }); + commitMessages = commits.trim().split('\n'); + } + catch { + // Ignore + } + // Parse diff to get file info + const files = parseDiffFiles(diff); + spinner.text = 'Extracting ticket references...'; + // Run peer review analysis + const result = await integration.analyze({ + prTitle: title || 'Untitled PR', + prDescription: undefined, // Could extract from git commit body + branchName, + commitMessages, + diff, + files, + prSummary: prAnalysisResult.summary, + prRisks: prAnalysisResult.overallRisks, + prComplexity: prAnalysisResult.overallComplexity, + }); + spinner.succeed('Peer Review analysis complete'); + // Display peer review results + const output = formatPeerReviewOutput(result); + if (output) { + console.log(output); + } + if (verbose && result.ticketReferences.length > 0) { + console.log(chalk.gray('Ticket references found:')); + result.ticketReferences.forEach((ref) => { + console.log(chalk.gray(` - ${ref.key} (from ${ref.source}, confidence: ${ref.confidence}%)`)); + }); + } + return result; + } + catch (error) { + spinner.fail('Peer Review analysis failed'); + console.error(chalk.yellow(`⚠️ ${error.message || 'Unknown error'}`)); + console.log(chalk.gray(' The main PR analysis completed successfully.')); + console.log(chalk.gray(' Peer Review is an optional enhancement - check Jira configuration.')); + return null; + } +} +/** + * Parse diff to extract file information + */ +function parseDiffFiles(diff) { + const files = []; + const filePattern = /^diff --git a\/(.+?) b\/(.+?)$/gm; + let match; + while ((match = filePattern.exec(diff)) !== null) { + const filePath = match[2] !== '/dev/null' ? match[2] : match[1]; + const isNew = match[1] === '/dev/null' || match[1].startsWith('dev/null'); + const isDeleted = match[2] === '/dev/null'; + // Count additions and deletions (simplified) + const fileStart = match.index; + const nextFileMatch = filePattern.exec(diff); + const fileEnd = nextFileMatch ? nextFileMatch.index : diff.length; + filePattern.lastIndex = match.index + 1; // Reset to continue from after current match + const fileContent = diff.substring(fileStart, fileEnd); + const additions = (fileContent.match(/^\+[^+]/gm) || []).length; + const deletions = (fileContent.match(/^-[^-]/gm) || []).length; + files.push({ + path: filePath, + additions, + deletions, + status: isNew ? 'added' : isDeleted ? 'deleted' : 'modified', + }); + } + return files; +} //# sourceMappingURL=analyze.command.js.map \ No newline at end of file diff --git a/dist/cli/commands/analyze.command.js.map b/dist/cli/commands/analyze.command.js.map index 13c86f8..ea48ba2 100644 --- a/dist/cli/commands/analyze.command.js.map +++ b/dist/cli/commands/analyze.command.js.map @@ -1 +1 @@ -{"version":3,"file":"analyze.command.js","sourceRoot":"","sources":["../../../src/cli/commands/analyze.command.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"analyze.command.js","sourceRoot":"","sources":["../../../src/cli/commands/analyze.command.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/cli/commands/config.command.js b/dist/cli/commands/config.command.js index 5242701..6736e96 100644 --- a/dist/cli/commands/config.command.js +++ b/dist/cli/commands/config.command.js @@ -8,12 +8,13 @@ const DEFAULT_CONFIG = { anthropic: '', openai: '', google: '', + zhipu: '', }, ai: { - provider: 'claude', + provider: 'anthropic', model: 'claude-sonnet-4-5-20250929', temperature: 0.2, - maxTokens: 2000, + maxTokens: 50000, }, analysis: { defaultMode: 'full', @@ -42,6 +43,16 @@ const DEFAULT_CONFIG = { showStrategy: true, showRecommendations: true, }, + peerReview: { + enabled: true, + useMcp: false, + analyzeAcceptanceCriteria: true, + rateTicketQuality: true, + generateTestSuggestions: true, + checkScopeCreep: true, + includeTicketDetails: true, + verbose: false, + }, }; /** * Find existing config file in root directory only diff --git a/dist/cli/commands/config.command.js.map b/dist/cli/commands/config.command.js.map index b1608b2..38e46a8 100644 --- a/dist/cli/commands/config.command.js.map +++ b/dist/cli/commands/config.command.js.map @@ -1 +1 @@ -{"version":3,"file":"config.command.js","sourceRoot":"","sources":["../../../src/cli/commands/config.command.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"config.command.js","sourceRoot":"","sources":["../../../src/cli/commands/config.command.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/cli/commands/help.command.js b/dist/cli/commands/help.command.js index 8024f2a..c2dff9c 100644 --- a/dist/cli/commands/help.command.js +++ b/dist/cli/commands/help.command.js @@ -39,7 +39,7 @@ export function displayHelp() { console.log(' 4. Fallback to origin/main'); console.log(' Use --branch to override for a single analysis\n'); console.log(chalk.dim(' Advanced Options:')); - console.log(' --provider AI provider: anthropic|openai|google'); + console.log(' --provider AI provider: anthropic|openai|google|zhipu'); console.log(' --model Specific model to use'); console.log(' --title PR title (auto-detected from git)'); console.log(' --max-cost Maximum cost limit (default: $5.00)'); diff --git a/dist/cli/commands/help.command.js.map b/dist/cli/commands/help.command.js.map index 1aa82f6..719eeed 100644 --- a/dist/cli/commands/help.command.js.map +++ b/dist/cli/commands/help.command.js.map @@ -1 +1 @@ -{"version":3,"file":"help.command.js","sourceRoot":"","sources":["../../../src/cli/commands/help.command.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"help.command.js","sourceRoot":"","sources":["../../../src/cli/commands/help.command.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/cli/index.js b/dist/cli/index.js index 0a26553..c0c83dd 100644 --- a/dist/cli/index.js +++ b/dist/cli/index.js @@ -5,6 +5,7 @@ import { Command } from 'commander'; import { analyzePR } from './commands/analyze.command.js'; import { registerConfigCommand } from './commands/config.command.js'; import { registerHelpCommand } from './commands/help.command.js'; +import { registerDashboardCommand } from './commands/dashboard.command.js'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; // __dirname workaround for ES modules @@ -27,7 +28,7 @@ program .option('--staged', 'Analyze staged changes (git diff --staged)') .option('--branch ', 'Analyze against specific branch') .option('--title ', 'PR title (auto-detected from git)') - .option('--provider ', 'AI provider (anthropic|openai|google)') + .option('--provider ', 'AI provider (anthropic|openai|google|zhipu)') .option('--model ', 'Specific model to use') .option('--agent', 'Force intelligent agent (recommended for large diffs)') .option('--summary', 'Show summary only') @@ -36,10 +37,17 @@ program .option('--full', 'Show all modes (default)', true) .option('--arch-docs', 'Use architecture documentation from .arch-docs folder (auto-detected by default)') .option('--max-cost ', 'Maximum cost in dollars', '5.0') + .option('--show-classification', 'Show project type classification (business logic vs QA)', false) + .option('--scan-coverage', 'Run test coverage analysis using nyc/istanbul', false) + .option('--show-coverage', 'Display coverage metrics if available', false) + .option('--show-static-analysis', 'Run and display ESLint static analysis results', false) + .option('--peer-review', 'Enable Jira peer review integration', false) .option('--verbose', 'Enable verbose output', false) .action(analyzePR); // Config command registerConfigCommand(program); +// Dashboard command +registerDashboardCommand(program); // Help command registerHelpCommand(program); // Parse CLI arguments diff --git a/dist/cli/index.js.map b/dist/cli/index.js.map index f5b4186..55ed8de 100644 --- a/dist/cli/index.js.map +++ b/dist/cli/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,sCAAsC;AACtC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;AACtE,iCAAiC;AACjC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAC1C,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,4DAA4D,CAAC;KACzE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAEhC,oDAAoD;AACpD,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,eAAe,EAAE,4BAA4B,CAAC;KACrD,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;KAC9C,MAAM,CAAC,UAAU,EAAE,4CAA4C,CAAC;KAChE,MAAM,CAAC,iBAAiB,EAAE,iCAAiC,CAAC;KAC5D,MAAM,CAAC,gBAAgB,EAAE,mCAAmC,CAAC;KAC7D,MAAM,CAAC,uBAAuB,EAAE,uCAAuC,CAAC;KACxE,MAAM,CAAC,iBAAiB,EAAE,uBAAuB,CAAC;KAClD,MAAM,CAAC,SAAS,EAAE,uDAAuD,CAAC;KAC1E,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAAC;KACxC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC;KACpC,MAAM,CAAC,cAAc,EAAE,sBAAsB,CAAC;KAC9C,MAAM,CAAC,QAAQ,EAAE,0BAA0B,EAAE,IAAI,CAAC;KAClD,MAAM,CAAC,aAAa,EAAE,kFAAkF,CAAC;KACzG,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,EAAE,KAAK,CAAC;KAChE,MAAM,CAAC,WAAW,EAAE,uBAAuB,EAAE,KAAK,CAAC;KACnD,MAAM,CAAC,SAAS,CAAC,CAAC;AAErB,iBAAiB;AACjB,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAE/B,eAAe;AACf,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,sBAAsB;AACtB,OAAO,CAAC,KAAK,EAAE,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,sCAAsC;AACtC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;AACtE,iCAAiC;AACjC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAC1C,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,4DAA4D,CAAC;KACzE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAEhC,oDAAoD;AACpD,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,eAAe,EAAE,4BAA4B,CAAC;KACrD,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;KAC9C,MAAM,CAAC,UAAU,EAAE,4CAA4C,CAAC;KAChE,MAAM,CAAC,iBAAiB,EAAE,iCAAiC,CAAC;KAC5D,MAAM,CAAC,gBAAgB,EAAE,mCAAmC,CAAC;KAC7D,MAAM,CAAC,uBAAuB,EAAE,6CAA6C,CAAC;KAC9E,MAAM,CAAC,iBAAiB,EAAE,uBAAuB,CAAC;KAClD,MAAM,CAAC,SAAS,EAAE,uDAAuD,CAAC;KAC1E,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAAC;KACxC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC;KACpC,MAAM,CAAC,cAAc,EAAE,sBAAsB,CAAC;KAC9C,MAAM,CAAC,QAAQ,EAAE,0BAA0B,EAAE,IAAI,CAAC;KAClD,MAAM,CAAC,aAAa,EAAE,kFAAkF,CAAC;KACzG,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,EAAE,KAAK,CAAC;KAChE,MAAM,CAAC,uBAAuB,EAAE,yDAAyD,EAAE,KAAK,CAAC;KACjG,MAAM,CAAC,iBAAiB,EAAE,+CAA+C,EAAE,KAAK,CAAC;KACjF,MAAM,CAAC,iBAAiB,EAAE,uCAAuC,EAAE,KAAK,CAAC;KACzE,MAAM,CAAC,wBAAwB,EAAE,gDAAgD,EAAE,KAAK,CAAC;KACzF,MAAM,CAAC,eAAe,EAAE,qCAAqC,EAAE,KAAK,CAAC;KACrE,MAAM,CAAC,WAAW,EAAE,uBAAuB,EAAE,KAAK,CAAC;KACnD,MAAM,CAAC,SAAS,CAAC,CAAC;AAErB,iBAAiB;AACjB,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAE/B,oBAAoB;AACpB,wBAAwB,CAAC,OAAO,CAAC,CAAC;AAElC,eAAe;AACf,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,sBAAsB;AACtB,OAAO,CAAC,KAAK,EAAE,CAAC"} \ No newline at end of file diff --git a/dist/cli/utils/config-loader.d.ts b/dist/cli/utils/config-loader.d.ts index a39e635..1658d57 100644 --- a/dist/cli/utils/config-loader.d.ts +++ b/dist/cli/utils/config-loader.d.ts @@ -3,6 +3,7 @@ export interface UserConfig { anthropic?: string; openai?: string; google?: string; + zhipu?: string; }; ai?: { provider?: string; @@ -29,6 +30,28 @@ export interface UserConfig { showStrategy?: boolean; showRecommendations?: boolean; }; + /** + * Peer Review configuration - integrates with issue trackers (Jira, etc.) + * to validate PRs against tickets and acceptance criteria + */ + peerReview?: { + enabled?: boolean; + provider?: string; + useMcp?: boolean; + instanceUrl?: string; + email?: string; + apiToken?: string; + defaultProject?: string; + acceptanceCriteriaField?: string; + storyPointsField?: string; + ticketPatterns?: string[]; + analyzeAcceptanceCriteria?: boolean; + rateTicketQuality?: boolean; + generateTestSuggestions?: boolean; + checkScopeCreep?: boolean; + includeTicketDetails?: boolean; + verbose?: boolean; + }; } /** * Find config file in current directory or parent directories diff --git a/dist/cli/utils/config-loader.js b/dist/cli/utils/config-loader.js index 43cb91a..137458f 100644 --- a/dist/cli/utils/config-loader.js +++ b/dist/cli/utils/config-loader.js @@ -130,6 +130,7 @@ export function getApiKey(provider, config) { anthropic: 'ANTHROPIC_API_KEY', openai: 'OPENAI_API_KEY', google: 'GOOGLE_API_KEY', + zhipu: 'ZHIPU_API_KEY', }; const envVar = envVarMap[provider.toLowerCase()]; if (envVar) { diff --git a/dist/cli/utils/config-loader.js.map b/dist/cli/utils/config-loader.js.map index d5a9e9d..0168443 100644 --- a/dist/cli/utils/config-loader.js.map +++ b/dist/cli/utils/config-loader.js.map @@ -1 +1 @@ -{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../../src/cli/utils/config-loader.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../../src/cli/utils/config-loader.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts deleted file mode 100644 index 246c3d8..0000000 --- a/dist/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Probot } from 'probot'; -declare const _default: (app: Probot) => void; -export default _default; diff --git a/dist/index.js b/dist/index.js index ea02011..192fd56 100644 --- a/dist/index.js +++ b/dist/index.js @@ -7631,6 +7631,719 @@ function removeHook(state, name, method) { } +/***/ }), + +/***/ 3909: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + + +const fs = __nccwpck_require__(9896); +const path = __nccwpck_require__(6928); +const util = __nccwpck_require__(2952); +const SqliteError = __nccwpck_require__(7483); + +let DEFAULT_ADDON; + +function Database(filenameGiven, options) { + if (new.target == null) { + return new Database(filenameGiven, options); + } + + // Apply defaults + let buffer; + if (Buffer.isBuffer(filenameGiven)) { + buffer = filenameGiven; + filenameGiven = ':memory:'; + } + if (filenameGiven == null) filenameGiven = ''; + if (options == null) options = {}; + + // Validate arguments + if (typeof filenameGiven !== 'string') throw new TypeError('Expected first argument to be a string'); + if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object'); + if ('readOnly' in options) throw new TypeError('Misspelled option "readOnly" should be "readonly"'); + if ('memory' in options) throw new TypeError('Option "memory" was removed in v7.0.0 (use ":memory:" filename instead)'); + + // Interpret options + const filename = filenameGiven.trim(); + const anonymous = filename === '' || filename === ':memory:'; + const readonly = util.getBooleanOption(options, 'readonly'); + const fileMustExist = util.getBooleanOption(options, 'fileMustExist'); + const timeout = 'timeout' in options ? options.timeout : 5000; + const verbose = 'verbose' in options ? options.verbose : null; + const nativeBinding = 'nativeBinding' in options ? options.nativeBinding : null; + + // Validate interpreted options + if (readonly && anonymous && !buffer) throw new TypeError('In-memory/temporary databases cannot be readonly'); + if (!Number.isInteger(timeout) || timeout < 0) throw new TypeError('Expected the "timeout" option to be a positive integer'); + if (timeout > 0x7fffffff) throw new RangeError('Option "timeout" cannot be greater than 2147483647'); + if (verbose != null && typeof verbose !== 'function') throw new TypeError('Expected the "verbose" option to be a function'); + if (nativeBinding != null && typeof nativeBinding !== 'string' && typeof nativeBinding !== 'object') throw new TypeError('Expected the "nativeBinding" option to be a string or addon object'); + + // Load the native addon + let addon; + if (nativeBinding == null) { + addon = DEFAULT_ADDON || (DEFAULT_ADDON = __WEBPACK_EXTERNAL_createRequire(import.meta.url)(__nccwpck_require__.ab + "build/Release/better_sqlite3.node")); + } else if (typeof nativeBinding === 'string') { + // See + const requireFunc = typeof __WEBPACK_EXTERNAL_createRequire(import.meta.url) === 'function' ? eval("require") : __WEBPACK_EXTERNAL_createRequire(import.meta.url); + addon = requireFunc(path.resolve(nativeBinding).replace(/(\.node)?$/, '.node')); + } else { + // See + addon = nativeBinding; + } + + if (!addon.isInitialized) { + addon.setErrorConstructor(SqliteError); + addon.isInitialized = true; + } + + // Make sure the specified directory exists + if (!anonymous && !filename.startsWith('file:') && !fs.existsSync(path.dirname(filename))) { + throw new TypeError('Cannot open database because the directory does not exist'); + } + + Object.defineProperties(this, { + [util.cppdb]: { value: new addon.Database(filename, filenameGiven, anonymous, readonly, fileMustExist, timeout, verbose || null, buffer || null) }, + ...wrappers.getters, + }); +} + +const wrappers = __nccwpck_require__(5463); +Database.prototype.prepare = wrappers.prepare; +Database.prototype.transaction = __nccwpck_require__(6695); +Database.prototype.pragma = __nccwpck_require__(8127); +Database.prototype.backup = __nccwpck_require__(6017); +Database.prototype.serialize = __nccwpck_require__(2161); +Database.prototype.function = __nccwpck_require__(3943); +Database.prototype.aggregate = __nccwpck_require__(4096); +Database.prototype.table = __nccwpck_require__(1355); +Database.prototype.loadExtension = wrappers.loadExtension; +Database.prototype.exec = wrappers.exec; +Database.prototype.close = wrappers.close; +Database.prototype.defaultSafeIntegers = wrappers.defaultSafeIntegers; +Database.prototype.unsafeMode = wrappers.unsafeMode; +Database.prototype[util.inspect] = __nccwpck_require__(9595); + +module.exports = Database; + + +/***/ }), + +/***/ 4918: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + + +module.exports = __nccwpck_require__(3909); +module.exports.SqliteError = __nccwpck_require__(7483); + + +/***/ }), + +/***/ 4096: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + + +const { getBooleanOption, cppdb } = __nccwpck_require__(2952); + +module.exports = function defineAggregate(name, options) { + // Validate arguments + if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string'); + if (typeof options !== 'object' || options === null) throw new TypeError('Expected second argument to be an options object'); + if (!name) throw new TypeError('User-defined function name cannot be an empty string'); + + // Interpret options + const start = 'start' in options ? options.start : null; + const step = getFunctionOption(options, 'step', true); + const inverse = getFunctionOption(options, 'inverse', false); + const result = getFunctionOption(options, 'result', false); + const safeIntegers = 'safeIntegers' in options ? +getBooleanOption(options, 'safeIntegers') : 2; + const deterministic = getBooleanOption(options, 'deterministic'); + const directOnly = getBooleanOption(options, 'directOnly'); + const varargs = getBooleanOption(options, 'varargs'); + let argCount = -1; + + // Determine argument count + if (!varargs) { + argCount = Math.max(getLength(step), inverse ? getLength(inverse) : 0); + if (argCount > 0) argCount -= 1; + if (argCount > 100) throw new RangeError('User-defined functions cannot have more than 100 arguments'); + } + + this[cppdb].aggregate(start, step, inverse, result, name, argCount, safeIntegers, deterministic, directOnly); + return this; +}; + +const getFunctionOption = (options, key, required) => { + const value = key in options ? options[key] : null; + if (typeof value === 'function') return value; + if (value != null) throw new TypeError(`Expected the "${key}" option to be a function`); + if (required) throw new TypeError(`Missing required option "${key}"`); + return null; +}; + +const getLength = ({ length }) => { + if (Number.isInteger(length) && length >= 0) return length; + throw new TypeError('Expected function.length to be a positive integer'); +}; + + +/***/ }), + +/***/ 6017: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + + +const fs = __nccwpck_require__(9896); +const path = __nccwpck_require__(6928); +const { promisify } = __nccwpck_require__(9023); +const { cppdb } = __nccwpck_require__(2952); +const fsAccess = promisify(fs.access); + +module.exports = async function backup(filename, options) { + if (options == null) options = {}; + + // Validate arguments + if (typeof filename !== 'string') throw new TypeError('Expected first argument to be a string'); + if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object'); + + // Interpret options + filename = filename.trim(); + const attachedName = 'attached' in options ? options.attached : 'main'; + const handler = 'progress' in options ? options.progress : null; + + // Validate interpreted options + if (!filename) throw new TypeError('Backup filename cannot be an empty string'); + if (filename === ':memory:') throw new TypeError('Invalid backup filename ":memory:"'); + if (typeof attachedName !== 'string') throw new TypeError('Expected the "attached" option to be a string'); + if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string'); + if (handler != null && typeof handler !== 'function') throw new TypeError('Expected the "progress" option to be a function'); + + // Make sure the specified directory exists + await fsAccess(path.dirname(filename)).catch(() => { + throw new TypeError('Cannot save backup because the directory does not exist'); + }); + + const isNewFile = await fsAccess(filename).then(() => false, () => true); + return runBackup(this[cppdb].backup(this, attachedName, filename, isNewFile), handler || null); +}; + +const runBackup = (backup, handler) => { + let rate = 0; + let useDefault = true; + + return new Promise((resolve, reject) => { + setImmediate(function step() { + try { + const progress = backup.transfer(rate); + if (!progress.remainingPages) { + backup.close(); + resolve(progress); + return; + } + if (useDefault) { + useDefault = false; + rate = 100; + } + if (handler) { + const ret = handler(progress); + if (ret !== undefined) { + if (typeof ret === 'number' && ret === ret) rate = Math.max(0, Math.min(0x7fffffff, Math.round(ret))); + else throw new TypeError('Expected progress callback to return a number or undefined'); + } + } + setImmediate(step); + } catch (err) { + backup.close(); + reject(err); + } + }); + }); +}; + + +/***/ }), + +/***/ 3943: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + + +const { getBooleanOption, cppdb } = __nccwpck_require__(2952); + +module.exports = function defineFunction(name, options, fn) { + // Apply defaults + if (options == null) options = {}; + if (typeof options === 'function') { fn = options; options = {}; } + + // Validate arguments + if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string'); + if (typeof fn !== 'function') throw new TypeError('Expected last argument to be a function'); + if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object'); + if (!name) throw new TypeError('User-defined function name cannot be an empty string'); + + // Interpret options + const safeIntegers = 'safeIntegers' in options ? +getBooleanOption(options, 'safeIntegers') : 2; + const deterministic = getBooleanOption(options, 'deterministic'); + const directOnly = getBooleanOption(options, 'directOnly'); + const varargs = getBooleanOption(options, 'varargs'); + let argCount = -1; + + // Determine argument count + if (!varargs) { + argCount = fn.length; + if (!Number.isInteger(argCount) || argCount < 0) throw new TypeError('Expected function.length to be a positive integer'); + if (argCount > 100) throw new RangeError('User-defined functions cannot have more than 100 arguments'); + } + + this[cppdb].function(fn, name, argCount, safeIntegers, deterministic, directOnly); + return this; +}; + + +/***/ }), + +/***/ 9595: +/***/ ((module) => { + + +const DatabaseInspection = function Database() {}; + +module.exports = function inspect(depth, opts) { + return Object.assign(new DatabaseInspection(), this); +}; + + + +/***/ }), + +/***/ 8127: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + + +const { getBooleanOption, cppdb } = __nccwpck_require__(2952); + +module.exports = function pragma(source, options) { + if (options == null) options = {}; + if (typeof source !== 'string') throw new TypeError('Expected first argument to be a string'); + if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object'); + const simple = getBooleanOption(options, 'simple'); + + const stmt = this[cppdb].prepare(`PRAGMA ${source}`, this, true); + return simple ? stmt.pluck().get() : stmt.all(); +}; + + +/***/ }), + +/***/ 2161: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + + +const { cppdb } = __nccwpck_require__(2952); + +module.exports = function serialize(options) { + if (options == null) options = {}; + + // Validate arguments + if (typeof options !== 'object') throw new TypeError('Expected first argument to be an options object'); + + // Interpret and validate options + const attachedName = 'attached' in options ? options.attached : 'main'; + if (typeof attachedName !== 'string') throw new TypeError('Expected the "attached" option to be a string'); + if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string'); + + return this[cppdb].serialize(attachedName); +}; + + +/***/ }), + +/***/ 1355: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + + +const { cppdb } = __nccwpck_require__(2952); + +module.exports = function defineTable(name, factory) { + // Validate arguments + if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string'); + if (!name) throw new TypeError('Virtual table module name cannot be an empty string'); + + // Determine whether the module is eponymous-only or not + let eponymous = false; + if (typeof factory === 'object' && factory !== null) { + eponymous = true; + factory = defer(parseTableDefinition(factory, 'used', name)); + } else { + if (typeof factory !== 'function') throw new TypeError('Expected second argument to be a function or a table definition object'); + factory = wrapFactory(factory); + } + + this[cppdb].table(factory, name, eponymous); + return this; +}; + +function wrapFactory(factory) { + return function virtualTableFactory(moduleName, databaseName, tableName, ...args) { + const thisObject = { + module: moduleName, + database: databaseName, + table: tableName, + }; + + // Generate a new table definition by invoking the factory + const def = apply.call(factory, thisObject, args); + if (typeof def !== 'object' || def === null) { + throw new TypeError(`Virtual table module "${moduleName}" did not return a table definition object`); + } + + return parseTableDefinition(def, 'returned', moduleName); + }; +} + +function parseTableDefinition(def, verb, moduleName) { + // Validate required properties + if (!hasOwnProperty.call(def, 'rows')) { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "rows" property`); + } + if (!hasOwnProperty.call(def, 'columns')) { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "columns" property`); + } + + // Validate "rows" property + const rows = def.rows; + if (typeof rows !== 'function' || Object.getPrototypeOf(rows) !== GeneratorFunctionPrototype) { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "rows" property (should be a generator function)`); + } + + // Validate "columns" property + let columns = def.columns; + if (!Array.isArray(columns) || !(columns = [...columns]).every(x => typeof x === 'string')) { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "columns" property (should be an array of strings)`); + } + if (columns.length !== new Set(columns).size) { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate column names`); + } + if (!columns.length) { + throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with zero columns`); + } + + // Validate "parameters" property + let parameters; + if (hasOwnProperty.call(def, 'parameters')) { + parameters = def.parameters; + if (!Array.isArray(parameters) || !(parameters = [...parameters]).every(x => typeof x === 'string')) { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "parameters" property (should be an array of strings)`); + } + } else { + parameters = inferParameters(rows); + } + if (parameters.length !== new Set(parameters).size) { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate parameter names`); + } + if (parameters.length > 32) { + throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with more than the maximum number of 32 parameters`); + } + for (const parameter of parameters) { + if (columns.includes(parameter)) { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with column "${parameter}" which was ambiguously defined as both a column and parameter`); + } + } + + // Validate "safeIntegers" option + let safeIntegers = 2; + if (hasOwnProperty.call(def, 'safeIntegers')) { + const bool = def.safeIntegers; + if (typeof bool !== 'boolean') { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "safeIntegers" property (should be a boolean)`); + } + safeIntegers = +bool; + } + + // Validate "directOnly" option + let directOnly = false; + if (hasOwnProperty.call(def, 'directOnly')) { + directOnly = def.directOnly; + if (typeof directOnly !== 'boolean') { + throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "directOnly" property (should be a boolean)`); + } + } + + // Generate SQL for the virtual table definition + const columnDefinitions = [ + ...parameters.map(identifier).map(str => `${str} HIDDEN`), + ...columns.map(identifier), + ]; + return [ + `CREATE TABLE x(${columnDefinitions.join(', ')});`, + wrapGenerator(rows, new Map(columns.map((x, i) => [x, parameters.length + i])), moduleName), + parameters, + safeIntegers, + directOnly, + ]; +} + +function wrapGenerator(generator, columnMap, moduleName) { + return function* virtualTable(...args) { + /* + We must defensively clone any buffers in the arguments, because + otherwise the generator could mutate one of them, which would cause + us to return incorrect values for hidden columns, potentially + corrupting the database. + */ + const output = args.map(x => Buffer.isBuffer(x) ? Buffer.from(x) : x); + for (let i = 0; i < columnMap.size; ++i) { + output.push(null); // Fill with nulls to prevent gaps in array (v8 optimization) + } + for (const row of generator(...args)) { + if (Array.isArray(row)) { + extractRowArray(row, output, columnMap.size, moduleName); + yield output; + } else if (typeof row === 'object' && row !== null) { + extractRowObject(row, output, columnMap, moduleName); + yield output; + } else { + throw new TypeError(`Virtual table module "${moduleName}" yielded something that isn't a valid row object`); + } + } + }; +} + +function extractRowArray(row, output, columnCount, moduleName) { + if (row.length !== columnCount) { + throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an incorrect number of columns`); + } + const offset = output.length - columnCount; + for (let i = 0; i < columnCount; ++i) { + output[i + offset] = row[i]; + } +} + +function extractRowObject(row, output, columnMap, moduleName) { + let count = 0; + for (const key of Object.keys(row)) { + const index = columnMap.get(key); + if (index === undefined) { + throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an undeclared column "${key}"`); + } + output[index] = row[key]; + count += 1; + } + if (count !== columnMap.size) { + throw new TypeError(`Virtual table module "${moduleName}" yielded a row with missing columns`); + } +} + +function inferParameters({ length }) { + if (!Number.isInteger(length) || length < 0) { + throw new TypeError('Expected function.length to be a positive integer'); + } + const params = []; + for (let i = 0; i < length; ++i) { + params.push(`$${i + 1}`); + } + return params; +} + +const { hasOwnProperty } = Object.prototype; +const { apply } = Function.prototype; +const GeneratorFunctionPrototype = Object.getPrototypeOf(function*(){}); +const identifier = str => `"${str.replace(/"/g, '""')}"`; +const defer = x => () => x; + + +/***/ }), + +/***/ 6695: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + + +const { cppdb } = __nccwpck_require__(2952); +const controllers = new WeakMap(); + +module.exports = function transaction(fn) { + if (typeof fn !== 'function') throw new TypeError('Expected first argument to be a function'); + + const db = this[cppdb]; + const controller = getController(db, this); + const { apply } = Function.prototype; + + // Each version of the transaction function has these same properties + const properties = { + default: { value: wrapTransaction(apply, fn, db, controller.default) }, + deferred: { value: wrapTransaction(apply, fn, db, controller.deferred) }, + immediate: { value: wrapTransaction(apply, fn, db, controller.immediate) }, + exclusive: { value: wrapTransaction(apply, fn, db, controller.exclusive) }, + database: { value: this, enumerable: true }, + }; + + Object.defineProperties(properties.default.value, properties); + Object.defineProperties(properties.deferred.value, properties); + Object.defineProperties(properties.immediate.value, properties); + Object.defineProperties(properties.exclusive.value, properties); + + // Return the default version of the transaction function + return properties.default.value; +}; + +// Return the database's cached transaction controller, or create a new one +const getController = (db, self) => { + let controller = controllers.get(db); + if (!controller) { + const shared = { + commit: db.prepare('COMMIT', self, false), + rollback: db.prepare('ROLLBACK', self, false), + savepoint: db.prepare('SAVEPOINT `\t_bs3.\t`', self, false), + release: db.prepare('RELEASE `\t_bs3.\t`', self, false), + rollbackTo: db.prepare('ROLLBACK TO `\t_bs3.\t`', self, false), + }; + controllers.set(db, controller = { + default: Object.assign({ begin: db.prepare('BEGIN', self, false) }, shared), + deferred: Object.assign({ begin: db.prepare('BEGIN DEFERRED', self, false) }, shared), + immediate: Object.assign({ begin: db.prepare('BEGIN IMMEDIATE', self, false) }, shared), + exclusive: Object.assign({ begin: db.prepare('BEGIN EXCLUSIVE', self, false) }, shared), + }); + } + return controller; +}; + +// Return a new transaction function by wrapping the given function +const wrapTransaction = (apply, fn, db, { begin, commit, rollback, savepoint, release, rollbackTo }) => function sqliteTransaction() { + let before, after, undo; + if (db.inTransaction) { + before = savepoint; + after = release; + undo = rollbackTo; + } else { + before = begin; + after = commit; + undo = rollback; + } + before.run(); + try { + const result = apply.call(fn, this, arguments); + if (result && typeof result.then === 'function') { + throw new TypeError('Transaction function cannot return a promise'); + } + after.run(); + return result; + } catch (ex) { + if (db.inTransaction) { + undo.run(); + if (undo !== rollback) after.run(); + } + throw ex; + } +}; + + +/***/ }), + +/***/ 5463: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + + +const { cppdb } = __nccwpck_require__(2952); + +exports.prepare = function prepare(sql) { + return this[cppdb].prepare(sql, this, false); +}; + +exports.exec = function exec(sql) { + this[cppdb].exec(sql); + return this; +}; + +exports.close = function close() { + this[cppdb].close(); + return this; +}; + +exports.loadExtension = function loadExtension(...args) { + this[cppdb].loadExtension(...args); + return this; +}; + +exports.defaultSafeIntegers = function defaultSafeIntegers(...args) { + this[cppdb].defaultSafeIntegers(...args); + return this; +}; + +exports.unsafeMode = function unsafeMode(...args) { + this[cppdb].unsafeMode(...args); + return this; +}; + +exports.getters = { + name: { + get: function name() { return this[cppdb].name; }, + enumerable: true, + }, + open: { + get: function open() { return this[cppdb].open; }, + enumerable: true, + }, + inTransaction: { + get: function inTransaction() { return this[cppdb].inTransaction; }, + enumerable: true, + }, + readonly: { + get: function readonly() { return this[cppdb].readonly; }, + enumerable: true, + }, + memory: { + get: function memory() { return this[cppdb].memory; }, + enumerable: true, + }, +}; + + +/***/ }), + +/***/ 7483: +/***/ ((module) => { + + +const descriptor = { value: 'SqliteError', writable: true, enumerable: false, configurable: true }; + +function SqliteError(message, code) { + if (new.target !== SqliteError) { + return new SqliteError(message, code); + } + if (typeof code !== 'string') { + throw new TypeError('Expected second argument to be a string'); + } + Error.call(this, message); + descriptor.value = '' + message; + Object.defineProperty(this, 'message', descriptor); + Error.captureStackTrace(this, SqliteError); + this.code = code; +} +Object.setPrototypeOf(SqliteError, Error); +Object.setPrototypeOf(SqliteError.prototype, Error.prototype); +Object.defineProperty(SqliteError.prototype, 'name', descriptor); +module.exports = SqliteError; + + +/***/ }), + +/***/ 2952: +/***/ ((__unused_webpack_module, exports) => { + + + +exports.getBooleanOption = (options, key) => { + let value = false; + if (key in options && typeof (value = options[key]) !== 'boolean') { + throw new TypeError(`Expected the "${key}" option to be a boolean`); + } + return value; +}; + +exports.cppdb = Symbol(); +exports.inspect = Symbol.for('nodejs.util.inspect.custom'); + + /***/ }), /***/ 9890: @@ -36482,964 +37195,264 @@ function parseParams (str) { module.exports = parseParams -/***/ }), - -/***/ 2561: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - - -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.InternalServerError = exports.RateLimitError = exports.UnprocessableEntityError = exports.ConflictError = exports.NotFoundError = exports.PermissionDeniedError = exports.AuthenticationError = exports.BadRequestError = exports.APIConnectionTimeoutError = exports.APIConnectionError = exports.APIUserAbortError = exports.APIError = exports.AnthropicError = void 0; -const errors_1 = __nccwpck_require__(7038); -class AnthropicError extends Error { -} -exports.AnthropicError = AnthropicError; -class APIError extends AnthropicError { - constructor(status, error, message, headers) { - super(`${APIError.makeMessage(status, error, message)}`); - this.status = status; - this.headers = headers; - this.requestID = headers?.get('request-id'); - this.error = error; - } - static makeMessage(status, error, message) { - const msg = error?.message ? - typeof error.message === 'string' ? - error.message - : JSON.stringify(error.message) - : error ? JSON.stringify(error) - : message; - if (status && msg) { - return `${status} ${msg}`; - } - if (status) { - return `${status} status code (no body)`; - } - if (msg) { - return msg; - } - return '(no status code or body)'; - } - static generate(status, errorResponse, message, headers) { - if (!status || !headers) { - return new APIConnectionError({ message, cause: (0, errors_1.castToError)(errorResponse) }); - } - const error = errorResponse; - if (status === 400) { - return new BadRequestError(status, error, message, headers); - } - if (status === 401) { - return new AuthenticationError(status, error, message, headers); - } - if (status === 403) { - return new PermissionDeniedError(status, error, message, headers); - } - if (status === 404) { - return new NotFoundError(status, error, message, headers); - } - if (status === 409) { - return new ConflictError(status, error, message, headers); - } - if (status === 422) { - return new UnprocessableEntityError(status, error, message, headers); - } - if (status === 429) { - return new RateLimitError(status, error, message, headers); - } - if (status >= 500) { - return new InternalServerError(status, error, message, headers); - } - return new APIError(status, error, message, headers); - } -} -exports.APIError = APIError; -class APIUserAbortError extends APIError { - constructor({ message } = {}) { - super(undefined, undefined, message || 'Request was aborted.', undefined); - } -} -exports.APIUserAbortError = APIUserAbortError; -class APIConnectionError extends APIError { - constructor({ message, cause }) { - super(undefined, undefined, message || 'Connection error.', undefined); - // in some environments the 'cause' property is already declared - // @ts-ignore - if (cause) - this.cause = cause; - } -} -exports.APIConnectionError = APIConnectionError; -class APIConnectionTimeoutError extends APIConnectionError { - constructor({ message } = {}) { - super({ message: message ?? 'Request timed out.' }); - } -} -exports.APIConnectionTimeoutError = APIConnectionTimeoutError; -class BadRequestError extends APIError { -} -exports.BadRequestError = BadRequestError; -class AuthenticationError extends APIError { -} -exports.AuthenticationError = AuthenticationError; -class PermissionDeniedError extends APIError { -} -exports.PermissionDeniedError = PermissionDeniedError; -class NotFoundError extends APIError { -} -exports.NotFoundError = NotFoundError; -class ConflictError extends APIError { -} -exports.ConflictError = ConflictError; -class UnprocessableEntityError extends APIError { -} -exports.UnprocessableEntityError = UnprocessableEntityError; -class RateLimitError extends APIError { -} -exports.RateLimitError = RateLimitError; -class InternalServerError extends APIError { -} -exports.InternalServerError = InternalServerError; -//# sourceMappingURL=error.js.map +/***/ }) -/***/ }), +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __nccwpck_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ id: moduleId, +/******/ loaded: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ var threw = true; +/******/ try { +/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__); +/******/ threw = false; +/******/ } finally { +/******/ if(threw) delete __webpack_module_cache__[moduleId]; +/******/ } +/******/ +/******/ // Flag the module as loaded +/******/ module.loaded = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __nccwpck_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __nccwpck_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __nccwpck_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/node module decorator */ +/******/ (() => { +/******/ __nccwpck_require__.nmd = (module) => { +/******/ module.paths = []; +/******/ if (!module.children) module.children = []; +/******/ return module; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/compat */ +/******/ +/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = new URL('.', import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/"; +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; -/***/ 7038: -/***/ ((__unused_webpack_module, exports) => { +// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js +var lib_core = __nccwpck_require__(7484); +// EXTERNAL MODULE: ./node_modules/@actions/github/lib/github.js +var github = __nccwpck_require__(3228); +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/_virtual/rolldown_runtime.js +//#region rolldown:runtime +var __defProp = Object.defineProperty; +var __export = (target, all) => { + for (var name in all) __defProp(target, name, { + get: all[name], + enumerable: true + }); +}; +//#endregion -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.castToError = void 0; -exports.isAbortError = isAbortError; -function isAbortError(err) { - return (typeof err === 'object' && - err !== null && - // Spec-compliant fetch implementations - (('name' in err && err.name === 'AbortError') || - // Expo fetch - ('message' in err && String(err.message).includes('FetchRequestCanceledException')))); -} -const castToError = (err) => { - if (err instanceof Error) - return err; - if (typeof err === 'object' && err !== null) { - try { - if (Object.prototype.toString.call(err) === '[object Error]') { - // @ts-ignore - not all envs have native support for cause yet - const error = new Error(err.message, err.cause ? { cause: err.cause } : {}); - if (err.stack) - error.stack = err.stack; - // @ts-ignore - not all envs have native support for cause yet - if (err.cause && !error.cause) - error.cause = err.cause; - if (err.name) - error.name = err.name; - return error; - } - } - catch { } - try { - return new Error(JSON.stringify(err)); - } - catch { } - } - return new Error(err); +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/singletons/async_local_storage/globals.js +//#region src/singletons/async_local_storage/globals.ts +const TRACING_ALS_KEY = Symbol.for("ls:tracing_async_local_storage"); +const globals_CONTEXT_VARIABLES_KEY = Symbol.for("lc:context_variables"); +const setGlobalAsyncLocalStorageInstance = (instance) => { + globalThis[TRACING_ALS_KEY] = instance; +}; +const globals_getGlobalAsyncLocalStorageInstance = () => { + return globalThis[TRACING_ALS_KEY]; }; -exports.castToError = castToError; -//# sourceMappingURL=errors.js.map -/***/ }), +//#endregion -/***/ 4253: -/***/ ((__unused_webpack_module, exports) => { +//# sourceMappingURL=globals.js.map +// EXTERNAL MODULE: ./node_modules/decamelize/index.js +var decamelize = __nccwpck_require__(8203); +// EXTERNAL MODULE: ./node_modules/camelcase/index.js +var camelcase = __nccwpck_require__(9890); +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/load/map_keys.js -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.__setModuleDefault = exports.__createBinding = void 0; -exports.__classPrivateFieldSet = __classPrivateFieldSet; -exports.__classPrivateFieldGet = __classPrivateFieldGet; -exports.__exportStar = __exportStar; -exports.__importStar = __importStar; -function __classPrivateFieldSet(receiver, state, value, kind, f) { - if (kind === "m") - throw new TypeError("Private method is not writable"); - if (kind === "a" && !f) - throw new TypeError("Private accessor was defined without a setter"); - if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) - throw new TypeError("Cannot write private member to an object whose class did not declare it"); - return kind === "a" ? f.call(receiver, value) : f ? (f.value = value) : state.set(receiver, value), value; + +//#region src/load/map_keys.ts +function keyToJson(key, map) { + return map?.[key] || decamelize(key); } -function __classPrivateFieldGet(receiver, state, kind, f) { - if (kind === "a" && !f) - throw new TypeError("Private accessor was defined without a getter"); - if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) - throw new TypeError("Cannot read private member from an object whose class did not declare it"); - return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +function keyFromJson(key, map) { + return map?.[key] || camelcase(key); } -var __createBinding = Object.create - ? function (o, m, k, k2) { - if (k2 === void 0) - k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { - enumerable: true, - get: function () { - return m[k]; - }, - }; - } - Object.defineProperty(o, k2, desc); - } - : function (o, m, k, k2) { - if (k2 === void 0) - k2 = k; - o[k2] = m[k]; - }; -exports.__createBinding = __createBinding; -function __exportStar(m, o) { - for (var p in m) - if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) - __createBinding(o, m, p); -} -var __setModuleDefault = Object.create - ? function (o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); - } - : function (o, v) { - o["default"] = v; - }; -exports.__setModuleDefault = __setModuleDefault; -var ownKeys = function (o) { - ownKeys = - Object.getOwnPropertyNames || - function (o2) { - var ar = []; - for (var k in o2) - if (Object.prototype.hasOwnProperty.call(o2, k)) - ar[ar.length] = k; - return ar; - }; - return ownKeys(o); -}; -function __importStar(mod) { - if (mod && mod.__esModule) - return mod; - var result = {}; - if (mod != null) { - for (var k = ownKeys(mod), i = 0; i < k.length; i++) - if (k[i] !== "default") - __createBinding(result, mod, k[i]); - } - __setModuleDefault(result, mod); - return result; +function mapKeys(fields, mapper, map) { + const mapped = {}; + for (const key in fields) if (Object.hasOwn(fields, key)) mapped[mapper(key, map)] = fields[key]; + return mapped; } +//#endregion -/***/ }), - -/***/ 3348: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - - -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -Object.defineProperty(exports, "__esModule", ({ value: true })); -const tslib_1 = __nccwpck_require__(4253); -tslib_1.__exportStar(__nccwpck_require__(537), exports); -tslib_1.__exportStar(__nccwpck_require__(2695), exports); -tslib_1.__exportStar(__nccwpck_require__(4644), exports); -tslib_1.__exportStar(__nccwpck_require__(4685), exports); -tslib_1.__exportStar(__nccwpck_require__(4248), exports); -tslib_1.__exportStar(__nccwpck_require__(2752), exports); -//# sourceMappingURL=utils.js.map - -/***/ }), - -/***/ 2695: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - - -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.fromBase64 = exports.toBase64 = void 0; -const error_1 = __nccwpck_require__(2561); -const bytes_1 = __nccwpck_require__(688); -const toBase64 = (data) => { - if (!data) - return ''; - if (typeof globalThis.Buffer !== 'undefined') { - return globalThis.Buffer.from(data).toString('base64'); - } - if (typeof data === 'string') { - data = (0, bytes_1.encodeUTF8)(data); - } - if (typeof btoa !== 'undefined') { - return btoa(String.fromCharCode.apply(null, data)); - } - throw new error_1.AnthropicError('Cannot generate base64 string; Expected `Buffer` or `btoa` to be defined'); -}; -exports.toBase64 = toBase64; -const fromBase64 = (str) => { - if (typeof globalThis.Buffer !== 'undefined') { - const buf = globalThis.Buffer.from(str, 'base64'); - return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); - } - if (typeof atob !== 'undefined') { - const bstr = atob(str); - const buf = new Uint8Array(bstr.length); - for (let i = 0; i < bstr.length; i++) { - buf[i] = bstr.charCodeAt(i); - } - return buf; - } - throw new error_1.AnthropicError('Cannot decode base64 string; Expected `Buffer` or `atob` to be defined'); -}; -exports.fromBase64 = fromBase64; -//# sourceMappingURL=base64.js.map - -/***/ }), - -/***/ 688: -/***/ ((__unused_webpack_module, exports) => { - - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.concatBytes = concatBytes; -exports.encodeUTF8 = encodeUTF8; -exports.decodeUTF8 = decodeUTF8; -function concatBytes(buffers) { - let length = 0; - for (const buffer of buffers) { - length += buffer.length; - } - const output = new Uint8Array(length); - let index = 0; - for (const buffer of buffers) { - output.set(buffer, index); - index += buffer.length; - } - return output; +//# sourceMappingURL=map_keys.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/load/validation.js +//#region src/load/validation.ts +/** +* Sentinel key used to mark escaped user objects during serialization. +* +* When a plain object contains 'lc' key (which could be confused with LC objects), +* we wrap it as `{"__lc_escaped__": {...original...}}`. +*/ +const LC_ESCAPED_KEY = "__lc_escaped__"; +/** +* Check if an object needs escaping to prevent confusion with LC objects. +* +* An object needs escaping if: +* 1. It has an `'lc'` key (could be confused with LC serialization format) +* 2. It has only the escape key (would be mistaken for an escaped object) +*/ +function needsEscaping(obj) { + return "lc" in obj || Object.keys(obj).length === 1 && LC_ESCAPED_KEY in obj; } -let encodeUTF8_; -function encodeUTF8(str) { - let encoder; - return (encodeUTF8_ ?? - ((encoder = new globalThis.TextEncoder()), (encodeUTF8_ = encoder.encode.bind(encoder))))(str); +/** +* Wrap an object in the escape marker. +* +* @example +* ```typescript +* {"key": "value"} // becomes {"__lc_escaped__": {"key": "value"}} +* ``` +*/ +function escapeObject(obj) { + return { [LC_ESCAPED_KEY]: obj }; } -let decodeUTF8_; -function decodeUTF8(bytes) { - let decoder; - return (decodeUTF8_ ?? - ((decoder = new globalThis.TextDecoder()), (decodeUTF8_ = decoder.decode.bind(decoder))))(bytes); +/** +* Check if an object is an escaped user object. +* +* @example +* ```typescript +* {"__lc_escaped__": {...}} // is an escaped object +* ``` +*/ +function isEscapedObject(obj) { + return Object.keys(obj).length === 1 && LC_ESCAPED_KEY in obj; } -//# sourceMappingURL=bytes.js.map - -/***/ }), - -/***/ 4644: -/***/ ((__unused_webpack_module, exports) => { - - -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.readEnv = void 0; /** - * Read an environment variable. - * - * Trims beginning and trailing whitespace. - * - * Will return undefined if the environment variable doesn't exist or cannot be accessed. - */ -const readEnv = (env) => { - if (typeof globalThis.process !== 'undefined') { - return globalThis.process.env?.[env]?.trim() ?? undefined; - } - if (typeof globalThis.Deno !== 'undefined') { - return globalThis.Deno.env?.get?.(env)?.trim(); - } - return undefined; -}; -exports.readEnv = readEnv; -//# sourceMappingURL=env.js.map - -/***/ }), - -/***/ 4685: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - - -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.formatRequestDetails = exports.parseLogLevel = void 0; -exports.loggerFor = loggerFor; -const values_1 = __nccwpck_require__(537); -const levelNumbers = { - off: 0, - error: 200, - warn: 300, - info: 400, - debug: 500, -}; -const parseLogLevel = (maybeLevel, sourceName, client) => { - if (!maybeLevel) { - return undefined; - } - if ((0, values_1.hasOwn)(levelNumbers, maybeLevel)) { - return maybeLevel; - } - loggerFor(client).warn(`${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify(Object.keys(levelNumbers))}`); - return undefined; -}; -exports.parseLogLevel = parseLogLevel; -function noop() { } -function makeLogFn(fnLevel, logger, logLevel) { - if (!logger || levelNumbers[fnLevel] > levelNumbers[logLevel]) { - return noop; - } - else { - // Don't wrap logger functions, we want the stacktrace intact! - return logger[fnLevel].bind(logger); - } +* Check if an object looks like a Serializable instance (duck typing). +*/ +function isSerializableLike(obj) { + return obj !== null && typeof obj === "object" && "lc_serializable" in obj && typeof obj.toJSON === "function"; } -const noopLogger = { - error: noop, - warn: noop, - info: noop, - debug: noop, -}; -let cachedLoggers = /* @__PURE__ */ new WeakMap(); -function loggerFor(client) { - const logger = client.logger; - const logLevel = client.logLevel ?? 'off'; - if (!logger) { - return noopLogger; - } - const cachedLogger = cachedLoggers.get(logger); - if (cachedLogger && cachedLogger[0] === logLevel) { - return cachedLogger[1]; - } - const levelLogger = { - error: makeLogFn('error', logger, logLevel), - warn: makeLogFn('warn', logger, logLevel), - info: makeLogFn('info', logger, logLevel), - debug: makeLogFn('debug', logger, logLevel), - }; - cachedLoggers.set(logger, [logLevel, levelLogger]); - return levelLogger; +/** +* Create a "not_implemented" serialization result for objects that cannot be serialized. +*/ +function createNotImplemented(obj) { + let id; + if (obj !== null && typeof obj === "object") if ("lc_id" in obj && Array.isArray(obj.lc_id)) id = obj.lc_id; + else id = [obj.constructor?.name ?? "Object"]; + else id = [typeof obj]; + return { + lc: 1, + type: "not_implemented", + id + }; +} +/** +* Escape a value if it needs escaping (contains `lc` key). +* +* This is a simpler version of `serializeValue` that doesn't handle Serializable +* objects - it's meant to be called on kwargs values that have already been +* processed by `toJSON()`. +* +* @param value - The value to potentially escape. +* @param pathSet - WeakSet to track ancestor objects in the current path to detect circular references. +* Objects are removed after processing to allow shared references (same object in +* multiple places) while still detecting true circular references (ancestor in descendant). +* @returns The value with any `lc`-containing objects wrapped in escape markers. +*/ +function escapeIfNeeded(value, pathSet = /* @__PURE__ */ new WeakSet()) { + if (value !== null && typeof value === "object" && !Array.isArray(value)) { + if (pathSet.has(value)) return createNotImplemented(value); + if (isSerializableLike(value)) return value; + pathSet.add(value); + const record = value; + if (needsEscaping(record)) { + pathSet.delete(value); + return escapeObject(record); + } + const result = {}; + for (const [key, val] of Object.entries(record)) result[key] = escapeIfNeeded(val, pathSet); + pathSet.delete(value); + return result; + } + if (Array.isArray(value)) return value.map((item) => escapeIfNeeded(item, pathSet)); + return value; +} +/** +* Unescape a value, processing escape markers in object values and arrays. +* +* When an escaped object is encountered (`{"__lc_escaped__": ...}`), it's +* unwrapped and the contents are returned AS-IS (no further processing). +* The contents represent user data that should not be modified. +* +* For regular objects and arrays, we recurse to find any nested escape markers. +* +* @param obj - The value to unescape. +* @returns The unescaped value. +*/ +function unescapeValue(obj) { + if (obj !== null && typeof obj === "object" && !Array.isArray(obj)) { + const record = obj; + if (isEscapedObject(record)) return record[LC_ESCAPED_KEY]; + const result = {}; + for (const [key, value] of Object.entries(record)) result[key] = unescapeValue(value); + return result; + } + if (Array.isArray(obj)) return obj.map((item) => unescapeValue(item)); + return obj; } -const formatRequestDetails = (details) => { - if (details.options) { - details.options = { ...details.options }; - delete details.options['headers']; // redundant + leaks internals - } - if (details.headers) { - details.headers = Object.fromEntries((details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map(([name, value]) => [ - name, - (name.toLowerCase() === 'x-api-key' || - name.toLowerCase() === 'authorization' || - name.toLowerCase() === 'cookie' || - name.toLowerCase() === 'set-cookie') ? - '***' - : value, - ])); - } - if ('retryOfRequestLogID' in details) { - if (details.retryOfRequestLogID) { - details.retryOf = details.retryOfRequestLogID; - } - delete details.retryOfRequestLogID; - } - return details; -}; -exports.formatRequestDetails = formatRequestDetails; -//# sourceMappingURL=log.js.map - -/***/ }), - -/***/ 2752: -/***/ ((__unused_webpack_module, exports) => { +//#endregion -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.sleep = void 0; -const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); -exports.sleep = sleep; -//# sourceMappingURL=sleep.js.map +//# sourceMappingURL=validation.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/load/serializable.js -/***/ }), - -/***/ 4248: -/***/ ((__unused_webpack_module, exports) => { - - -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.uuid4 = void 0; -/** - * https://stackoverflow.com/a/2117523 - */ -let uuid4 = function () { - const { crypto } = globalThis; - if (crypto?.randomUUID) { - exports.uuid4 = crypto.randomUUID.bind(crypto); - return crypto.randomUUID(); - } - const u8 = new Uint8Array(1); - const randomByte = crypto ? () => crypto.getRandomValues(u8)[0] : () => (Math.random() * 0xff) & 0xff; - return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) => (+c ^ (randomByte() & (15 >> (+c / 4)))).toString(16)); -}; -exports.uuid4 = uuid4; -//# sourceMappingURL=uuid.js.map - -/***/ }), - -/***/ 537: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - - -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.pop = exports.safeJSON = exports.maybeCoerceBoolean = exports.maybeCoerceFloat = exports.maybeCoerceInteger = exports.coerceBoolean = exports.coerceFloat = exports.coerceInteger = exports.validatePositiveInteger = exports.ensurePresent = exports.isReadonlyArray = exports.isArray = exports.isAbsoluteURL = void 0; -exports.maybeObj = maybeObj; -exports.isEmptyObj = isEmptyObj; -exports.hasOwn = hasOwn; -exports.isObj = isObj; -const error_1 = __nccwpck_require__(2561); -// https://url.spec.whatwg.org/#url-scheme-string -const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i; -const isAbsoluteURL = (url) => { - return startsWithSchemeRegexp.test(url); -}; -exports.isAbsoluteURL = isAbsoluteURL; -let isArray = (val) => ((exports.isArray = Array.isArray), (0, exports.isArray)(val)); -exports.isArray = isArray; -exports.isReadonlyArray = exports.isArray; -/** Returns an object if the given value isn't an object, otherwise returns as-is */ -function maybeObj(x) { - if (typeof x !== 'object') { - return {}; - } - return x ?? {}; -} -// https://stackoverflow.com/a/34491287 -function isEmptyObj(obj) { - if (!obj) - return true; - for (const _k in obj) - return false; - return true; -} -// https://eslint.org/docs/latest/rules/no-prototype-builtins -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} -function isObj(obj) { - return obj != null && typeof obj === 'object' && !Array.isArray(obj); -} -const ensurePresent = (value) => { - if (value == null) { - throw new error_1.AnthropicError(`Expected a value to be given but received ${value} instead.`); - } - return value; -}; -exports.ensurePresent = ensurePresent; -const validatePositiveInteger = (name, n) => { - if (typeof n !== 'number' || !Number.isInteger(n)) { - throw new error_1.AnthropicError(`${name} must be an integer`); - } - if (n < 0) { - throw new error_1.AnthropicError(`${name} must be a positive integer`); - } - return n; -}; -exports.validatePositiveInteger = validatePositiveInteger; -const coerceInteger = (value) => { - if (typeof value === 'number') - return Math.round(value); - if (typeof value === 'string') - return parseInt(value, 10); - throw new error_1.AnthropicError(`Could not coerce ${value} (type: ${typeof value}) into a number`); -}; -exports.coerceInteger = coerceInteger; -const coerceFloat = (value) => { - if (typeof value === 'number') - return value; - if (typeof value === 'string') - return parseFloat(value); - throw new error_1.AnthropicError(`Could not coerce ${value} (type: ${typeof value}) into a number`); -}; -exports.coerceFloat = coerceFloat; -const coerceBoolean = (value) => { - if (typeof value === 'boolean') - return value; - if (typeof value === 'string') - return value === 'true'; - return Boolean(value); -}; -exports.coerceBoolean = coerceBoolean; -const maybeCoerceInteger = (value) => { - if (value == null) { - return undefined; - } - return (0, exports.coerceInteger)(value); -}; -exports.maybeCoerceInteger = maybeCoerceInteger; -const maybeCoerceFloat = (value) => { - if (value == null) { - return undefined; - } - return (0, exports.coerceFloat)(value); -}; -exports.maybeCoerceFloat = maybeCoerceFloat; -const maybeCoerceBoolean = (value) => { - if (value == null) { - return undefined; - } - return (0, exports.coerceBoolean)(value); -}; -exports.maybeCoerceBoolean = maybeCoerceBoolean; -const safeJSON = (text) => { - try { - return JSON.parse(text); - } - catch (err) { - return undefined; - } -}; -exports.safeJSON = safeJSON; -// Gets a value from an object, deletes the key, and returns the value (or undefined if not found) -const pop = (obj, key) => { - const value = obj[key]; - delete obj[key]; - return value; -}; -exports.pop = pop; -//# sourceMappingURL=values.js.map - -/***/ }), - -/***/ 1252: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -var __webpack_unused_export__; - -__webpack_unused_export__ = ({ value: true }); -exports.W = transformJSONSchema; -const utils_1 = __nccwpck_require__(3348); -// Supported string formats -const SUPPORTED_STRING_FORMATS = new Set([ - 'date-time', - 'time', - 'date', - 'duration', - 'email', - 'hostname', - 'uri', - 'ipv4', - 'ipv6', - 'uuid', -]); -function deepClone(obj) { - return JSON.parse(JSON.stringify(obj)); -} -function transformJSONSchema(jsonSchema) { - const workingCopy = deepClone(jsonSchema); - return _transformJSONSchema(workingCopy); -} -function _transformJSONSchema(jsonSchema) { - const strictSchema = {}; - const ref = (0, utils_1.pop)(jsonSchema, '$ref'); - if (ref !== undefined) { - strictSchema['$ref'] = ref; - return strictSchema; - } - const defs = (0, utils_1.pop)(jsonSchema, '$defs'); - if (defs !== undefined) { - const strictDefs = {}; - strictSchema['$defs'] = strictDefs; - for (const [name, defSchema] of Object.entries(defs)) { - strictDefs[name] = _transformJSONSchema(defSchema); - } - } - const type = (0, utils_1.pop)(jsonSchema, 'type'); - const anyOf = (0, utils_1.pop)(jsonSchema, 'anyOf'); - const oneOf = (0, utils_1.pop)(jsonSchema, 'oneOf'); - const allOf = (0, utils_1.pop)(jsonSchema, 'allOf'); - if (Array.isArray(anyOf)) { - strictSchema['anyOf'] = anyOf.map((variant) => _transformJSONSchema(variant)); - } - else if (Array.isArray(oneOf)) { - strictSchema['anyOf'] = oneOf.map((variant) => _transformJSONSchema(variant)); - } - else if (Array.isArray(allOf)) { - strictSchema['allOf'] = allOf.map((entry) => _transformJSONSchema(entry)); - } - else { - if (type === undefined) { - throw new Error('JSON schema must have a type defined if anyOf/oneOf/allOf are not used'); - } - strictSchema['type'] = type; - } - const description = (0, utils_1.pop)(jsonSchema, 'description'); - if (description !== undefined) { - strictSchema['description'] = description; - } - const title = (0, utils_1.pop)(jsonSchema, 'title'); - if (title !== undefined) { - strictSchema['title'] = title; - } - if (type === 'object') { - const properties = (0, utils_1.pop)(jsonSchema, 'properties') || {}; - strictSchema['properties'] = Object.fromEntries(Object.entries(properties).map(([key, propSchema]) => [ - key, - _transformJSONSchema(propSchema), - ])); - (0, utils_1.pop)(jsonSchema, 'additionalProperties'); - strictSchema['additionalProperties'] = false; - const required = (0, utils_1.pop)(jsonSchema, 'required'); - if (required !== undefined) { - strictSchema['required'] = required; - } - } - else if (type === 'string') { - const format = (0, utils_1.pop)(jsonSchema, 'format'); - if (format !== undefined && SUPPORTED_STRING_FORMATS.has(format)) { - strictSchema['format'] = format; - } - else if (format !== undefined) { - jsonSchema['format'] = format; - } - } - else if (type === 'array') { - const items = (0, utils_1.pop)(jsonSchema, 'items'); - if (items !== undefined) { - strictSchema['items'] = _transformJSONSchema(items); - } - const minItems = (0, utils_1.pop)(jsonSchema, 'minItems'); - if (minItems !== undefined && (minItems === 0 || minItems === 1)) { - strictSchema['minItems'] = minItems; - } - else if (minItems !== undefined) { - jsonSchema['minItems'] = minItems; - } - } - if (Object.keys(jsonSchema).length > 0) { - const existingDescription = strictSchema['description']; - strictSchema['description'] = - (existingDescription ? existingDescription + '\n\n' : '') + - '{' + - Object.entries(jsonSchema) - .map(([key, value]) => `${key}: ${JSON.stringify(value)}`) - .join(', ') + - '}'; - } - return strictSchema; -} -//# sourceMappingURL=transform-json-schema.js.map - -/***/ }) - -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __nccwpck_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ id: moduleId, -/******/ loaded: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ var threw = true; -/******/ try { -/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__); -/******/ threw = false; -/******/ } finally { -/******/ if(threw) delete __webpack_module_cache__[moduleId]; -/******/ } -/******/ -/******/ // Flag the module as loaded -/******/ module.loaded = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ /* webpack/runtime/define property getters */ -/******/ (() => { -/******/ // define getter functions for harmony exports -/******/ __nccwpck_require__.d = (exports, definition) => { -/******/ for(var key in definition) { -/******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) { -/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); -/******/ } -/******/ } -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/hasOwnProperty shorthand */ -/******/ (() => { -/******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) -/******/ })(); -/******/ -/******/ /* webpack/runtime/make namespace object */ -/******/ (() => { -/******/ // define __esModule on exports -/******/ __nccwpck_require__.r = (exports) => { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/node module decorator */ -/******/ (() => { -/******/ __nccwpck_require__.nmd = (module) => { -/******/ module.paths = []; -/******/ if (!module.children) module.children = []; -/******/ return module; -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/compat */ -/******/ -/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = new URL('.', import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/"; -/******/ -/************************************************************************/ -var __webpack_exports__ = {}; - -// NAMESPACE OBJECT: ./node_modules/zod/v4/core/regexes.js -var regexes_namespaceObject = {}; -__nccwpck_require__.r(regexes_namespaceObject); -__nccwpck_require__.d(regexes_namespaceObject, { - base64: () => (base64), - base64url: () => (base64url), - bigint: () => (bigint), - boolean: () => (regexes_boolean), - browserEmail: () => (browserEmail), - cidrv4: () => (cidrv4), - cidrv6: () => (cidrv6), - cuid: () => (cuid), - cuid2: () => (cuid2), - date: () => (date), - datetime: () => (datetime), - domain: () => (domain), - duration: () => (duration), - e164: () => (e164), - email: () => (email), - emoji: () => (emoji), - extendedDuration: () => (extendedDuration), - guid: () => (guid), - hex: () => (hex), - hostname: () => (hostname), - html5Email: () => (html5Email), - idnEmail: () => (idnEmail), - integer: () => (integer), - ipv4: () => (ipv4), - ipv6: () => (ipv6), - ksuid: () => (ksuid), - lowercase: () => (lowercase), - mac: () => (mac), - md5_base64: () => (md5_base64), - md5_base64url: () => (md5_base64url), - md5_hex: () => (md5_hex), - nanoid: () => (nanoid), - "null": () => (_null), - number: () => (number), - rfc5322Email: () => (rfc5322Email), - sha1_base64: () => (sha1_base64), - sha1_base64url: () => (sha1_base64url), - sha1_hex: () => (sha1_hex), - sha256_base64: () => (sha256_base64), - sha256_base64url: () => (sha256_base64url), - sha256_hex: () => (sha256_hex), - sha384_base64: () => (sha384_base64), - sha384_base64url: () => (sha384_base64url), - sha384_hex: () => (sha384_hex), - sha512_base64: () => (sha512_base64), - sha512_base64url: () => (sha512_base64url), - sha512_hex: () => (sha512_hex), - string: () => (string), - time: () => (time), - ulid: () => (ulid), - undefined: () => (_undefined), - unicodeEmail: () => (unicodeEmail), - uppercase: () => (uppercase), - uuid: () => (uuid), - uuid4: () => (uuid4), - uuid6: () => (regexes_uuid6), - uuid7: () => (regexes_uuid7), - xid: () => (xid) -}); - -// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js -var core = __nccwpck_require__(7484); -// EXTERNAL MODULE: ./node_modules/@actions/github/lib/github.js -var github = __nccwpck_require__(3228); -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/_virtual/rolldown_runtime.js -//#region rolldown:runtime -var __defProp = Object.defineProperty; -var __export = (target, all) => { - for (var name in all) __defProp(target, name, { - get: all[name], - enumerable: true - }); -}; - -//#endregion - -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/singletons/async_local_storage/globals.js -//#region src/singletons/async_local_storage/globals.ts -const TRACING_ALS_KEY = Symbol.for("ls:tracing_async_local_storage"); -const globals_CONTEXT_VARIABLES_KEY = Symbol.for("lc:context_variables"); -const setGlobalAsyncLocalStorageInstance = (instance) => { - globalThis[TRACING_ALS_KEY] = instance; -}; -const globals_getGlobalAsyncLocalStorageInstance = () => { - return globalThis[TRACING_ALS_KEY]; -}; - -//#endregion - -//# sourceMappingURL=globals.js.map -// EXTERNAL MODULE: ./node_modules/decamelize/index.js -var decamelize = __nccwpck_require__(8203); -// EXTERNAL MODULE: ./node_modules/camelcase/index.js -var camelcase = __nccwpck_require__(9890); -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/load/map_keys.js - - - -//#region src/load/map_keys.ts -function keyToJson(key, map) { - return map?.[key] || decamelize(key); -} -function keyFromJson(key, map) { - return map?.[key] || camelcase(key); -} -function mapKeys(fields, mapper, map) { - const mapped = {}; - for (const key in fields) if (Object.hasOwn(fields, key)) mapped[mapper(key, map)] = fields[key]; - return mapped; -} - -//#endregion - -//# sourceMappingURL=map_keys.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/load/serializable.js @@ -37564,11 +37577,17 @@ var Serializable = class Serializable { } if (last in read && read[last] !== void 0) write[last] = write[last] || read[last]; }); + const escapedKwargs = {}; + const pathSet = /* @__PURE__ */ new WeakSet(); + pathSet.add(this); + for (const [key, value] of Object.entries(kwargs)) escapedKwargs[key] = escapeIfNeeded(value, pathSet); + const kwargsWithSecrets = Object.keys(secrets).length ? replaceSecrets(escapedKwargs, secrets) : escapedKwargs; + const processedKwargs = mapKeys(kwargsWithSecrets, keyToJson, aliases); return { lc: 1, type: "constructor", id: this.lc_id, - kwargs: mapKeys(Object.keys(secrets).length ? replaceSecrets(kwargs, secrets) : kwargs, keyToJson, aliases) + kwargs: processedKwargs }; } toJSONNotImplemented() { @@ -38606,7 +38625,7 @@ function convertToPrettyString(message) { lines.push(` ${tc.name} (${tc.id})`); lines.push(` Call ID: ${tc.id}`); lines.push(" Args:"); - for (const [key, value] of Object.entries(tc.args)) lines.push(` ${key}: ${value}`); + for (const [key, value] of Object.entries(tc.args)) lines.push(` ${key}: ${typeof value === "object" ? JSON.stringify(value) : value}`); } } } @@ -38704,6 +38723,7 @@ var BaseMessage = class extends Serializable { } [MESSAGE_SYMBOL] = true; id; + /** @inheritdoc */ name; content; additional_kwargs; @@ -38814,7 +38834,9 @@ var BaseMessage = class extends Serializable { function isOpenAIToolCallArray(value) { return Array.isArray(value) && value.every((v) => typeof v.index === "number"); } -function _mergeDicts(left = {}, right = {}) { +function _mergeDicts(left, right) { + if (left === void 0 && right === void 0) return void 0; + if (left === void 0 || right === void 0) return left ?? right; const merged = { ...left }; for (const [key, value] of Object.entries(right)) if (merged[key] == null) merged[key] = value; else if (value == null) continue; @@ -38825,8 +38847,10 @@ function _mergeDicts(left = {}, right = {}) { "name", "output_version", "model_provider" - ].includes(key)) merged[key] = value; - else merged[key] += value; + ].includes(key)) { + if (value) merged[key] = value; + } else merged[key] += value; + else if (typeof merged[key] === "number") merged[key] = merged[key] + value; else if (typeof merged[key] === "object" && !Array.isArray(merged[key])) merged[key] = _mergeDicts(merged[key], value); else if (Array.isArray(merged[key])) merged[key] = _mergeLists(merged[key], value); else if (merged[key] === value) continue; @@ -38854,8 +38878,8 @@ function _mergeLists(left, right) { } } function _mergeObj(left, right) { - if (!left && !right) throw new Error("Cannot merge two undefined objects."); - if (!left || !right) return left || right; + if (left === void 0 && right === void 0) return void 0; + if (left === void 0 || right === void 0) return left ?? right; else if (typeof left !== typeof right) throw new Error(`Cannot merge objects of different types.\nLeft ${typeof left}\nRight ${typeof right}`); else if (typeof left === "string" && typeof right === "string") return left + right; else if (Array.isArray(left) && Array.isArray(right)) return _mergeLists(left, right); @@ -39056,6 +39080,41 @@ function isToolMessageChunk(x) { //#endregion //# sourceMappingURL=tool.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/errors/index.js +//#region src/errors/index.ts +function addLangChainErrorFields(error, lc_error_code) { + error.lc_error_code = lc_error_code; + error.message = `${error.message}\n\nTroubleshooting URL: https://docs.langchain.com/oss/javascript/langchain/errors/${lc_error_code}/\n`; + return error; +} + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tools/utils.js +//#region src/tools/utils.ts +function _isToolCall(toolCall) { + return !!(toolCall && typeof toolCall === "object" && "type" in toolCall && toolCall.type === "tool_call"); +} +function _configHasToolCallId(config) { + return !!(config && typeof config === "object" && "toolCall" in config && config.toolCall != null && typeof config.toolCall === "object" && "id" in config.toolCall && typeof config.toolCall.id === "string"); +} +/** +* Custom error class used to handle exceptions related to tool input parsing. +* It extends the built-in `Error` class and adds an optional `output` +* property that can hold the output that caused the exception. +*/ +var ToolInputParsingException = class extends Error { + output; + constructor(message, output) { + super(message); + this.output = output; + } +}; + +//#endregion + +//# sourceMappingURL=utils.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/json.js //#region src/utils/json.ts function parseJsonMarkdown(s, parser = parsePartialJson) { @@ -39071,33 +39130,193 @@ function parseJsonMarkdown(s, parser = parsePartialJson) { if (closingFenceIndex !== -1) finalContent = contentAfterFence.substring(0, closingFenceIndex); return parser(finalContent.trim()); } -function parsePartialJson(s) { - if (typeof s === "undefined") return null; +/** +* Recursive descent partial JSON parser. +* @param s - The string to parse. +* @returns The parsed value. +* @throws Error if the input is a malformed JSON string. +*/ +function strictParsePartialJson(s) { try { return JSON.parse(s); } catch {} - let new_s = ""; - const stack = []; - let isInsideString = false; - let escaped = false; - for (let char of s) { - if (isInsideString) if (char === "\"" && !escaped) isInsideString = false; - else if (char === "\n" && !escaped) char = "\\n"; - else if (char === "\\") escaped = !escaped; - else escaped = false; - else if (char === "\"") { - isInsideString = true; - escaped = false; - } else if (char === "{") stack.push("}"); - else if (char === "[") stack.push("]"); - else if (char === "}" || char === "]") if (stack && stack[stack.length - 1] === char) stack.pop(); - else return null; - new_s += char; - } - if (isInsideString) new_s += "\""; - for (let i = stack.length - 1; i >= 0; i -= 1) new_s += stack[i]; + const buffer = s.trim(); + if (buffer.length === 0) throw new Error("Unexpected end of JSON input"); + let pos = 0; + function skipWhitespace() { + while (pos < buffer.length && /\s/.test(buffer[pos])) pos += 1; + } + function parseString() { + if (buffer[pos] !== "\"") throw new Error(`Expected '"' at position ${pos}, got '${buffer[pos]}'`); + pos += 1; + let result = ""; + let escaped = false; + while (pos < buffer.length) { + const char = buffer[pos]; + if (escaped) { + if (char === "n") result += "\n"; + else if (char === "t") result += " "; + else if (char === "r") result += "\r"; + else if (char === "\\") result += "\\"; + else if (char === "\"") result += "\""; + else if (char === "b") result += "\b"; + else if (char === "f") result += "\f"; + else if (char === "/") result += "/"; + else if (char === "u") { + const hex = buffer.substring(pos + 1, pos + 5); + if (/^[0-9A-Fa-f]{0,4}$/.test(hex)) { + if (hex.length === 4) result += String.fromCharCode(Number.parseInt(hex, 16)); + else result += `u${hex}`; + pos += hex.length; + } else throw new Error(`Invalid unicode escape sequence '\\u${hex}' at position ${pos}`); + } else throw new Error(`Invalid escape sequence '\\${char}' at position ${pos}`); + escaped = false; + } else if (char === "\\") escaped = true; + else if (char === "\"") { + pos += 1; + return result; + } else result += char; + pos += 1; + } + if (escaped) result += "\\"; + return result; + } + function parseNumber() { + const start = pos; + let numStr = ""; + if (buffer[pos] === "-") { + numStr += "-"; + pos += 1; + } + if (pos < buffer.length && buffer[pos] === "0") { + numStr += "0"; + pos += 1; + if (buffer[pos] >= "0" && buffer[pos] <= "9") throw new Error(`Invalid number at position ${start}`); + } + if (pos < buffer.length && buffer[pos] >= "1" && buffer[pos] <= "9") while (pos < buffer.length && buffer[pos] >= "0" && buffer[pos] <= "9") { + numStr += buffer[pos]; + pos += 1; + } + if (pos < buffer.length && buffer[pos] === ".") { + numStr += "."; + pos += 1; + while (pos < buffer.length && buffer[pos] >= "0" && buffer[pos] <= "9") { + numStr += buffer[pos]; + pos += 1; + } + } + if (pos < buffer.length && (buffer[pos] === "e" || buffer[pos] === "E")) { + numStr += buffer[pos]; + pos += 1; + if (pos < buffer.length && (buffer[pos] === "+" || buffer[pos] === "-")) { + numStr += buffer[pos]; + pos += 1; + } + while (pos < buffer.length && buffer[pos] >= "0" && buffer[pos] <= "9") { + numStr += buffer[pos]; + pos += 1; + } + } + if (numStr === "-") return -0; + const num = Number.parseFloat(numStr); + if (Number.isNaN(num)) { + pos = start; + throw new Error(`Invalid number '${numStr}' at position ${start}`); + } + return num; + } + function parseValue() { + skipWhitespace(); + if (pos >= buffer.length) throw new Error(`Unexpected end of input at position ${pos}`); + const char = buffer[pos]; + if (char === "{") return parseObject(); + if (char === "[") return parseArray(); + if (char === "\"") return parseString(); + if ("null".startsWith(buffer.substring(pos, pos + 4))) { + pos += Math.min(4, buffer.length - pos); + return null; + } + if ("true".startsWith(buffer.substring(pos, pos + 4))) { + pos += Math.min(4, buffer.length - pos); + return true; + } + if ("false".startsWith(buffer.substring(pos, pos + 5))) { + pos += Math.min(5, buffer.length - pos); + return false; + } + if (char === "-" || char >= "0" && char <= "9") return parseNumber(); + throw new Error(`Unexpected character '${char}' at position ${pos}`); + } + function parseArray() { + if (buffer[pos] !== "[") throw new Error(`Expected '[' at position ${pos}, got '${buffer[pos]}'`); + const arr = []; + pos += 1; + skipWhitespace(); + if (pos >= buffer.length) return arr; + if (buffer[pos] === "]") { + pos += 1; + return arr; + } + while (pos < buffer.length) { + skipWhitespace(); + if (pos >= buffer.length) return arr; + arr.push(parseValue()); + skipWhitespace(); + if (pos >= buffer.length) return arr; + if (buffer[pos] === "]") { + pos += 1; + return arr; + } else if (buffer[pos] === ",") { + pos += 1; + continue; + } + throw new Error(`Expected ',' or ']' at position ${pos}, got '${buffer[pos]}'`); + } + return arr; + } + function parseObject() { + if (buffer[pos] !== "{") throw new Error(`Expected '{' at position ${pos}, got '${buffer[pos]}'`); + const obj = {}; + pos += 1; + skipWhitespace(); + if (pos >= buffer.length) return obj; + if (buffer[pos] === "}") { + pos += 1; + return obj; + } + while (pos < buffer.length) { + skipWhitespace(); + if (pos >= buffer.length) return obj; + const key = parseString(); + skipWhitespace(); + if (pos >= buffer.length) return obj; + if (buffer[pos] !== ":") throw new Error(`Expected ':' at position ${pos}, got '${buffer[pos]}'`); + pos += 1; + skipWhitespace(); + if (pos >= buffer.length) return obj; + obj[key] = parseValue(); + skipWhitespace(); + if (pos >= buffer.length) return obj; + if (buffer[pos] === "}") { + pos += 1; + return obj; + } else if (buffer[pos] === ",") { + pos += 1; + continue; + } + throw new Error(`Expected ',' or '}' at position ${pos}, got '${buffer[pos]}'`); + } + return obj; + } + const value = parseValue(); + skipWhitespace(); + if (pos < buffer.length) throw new Error(`Unexpected character '${buffer[pos]}' at position ${pos}`); + return value; +} +function parsePartialJson(s) { try { - return JSON.parse(new_s); + if (typeof s === "undefined") return null; + return strictParsePartialJson(s); } catch { return null; } @@ -39106,6 +39325,320 @@ function parsePartialJson(s) { //#endregion //# sourceMappingURL=json.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/chat.js + + +//#region src/messages/chat.ts +/** +* Represents a chat message in a conversation. +*/ +var ChatMessage = class ChatMessage extends BaseMessage { + static lc_name() { + return "ChatMessage"; + } + type = "generic"; + role; + static _chatMessageClass() { + return ChatMessage; + } + constructor(fields, role) { + if (typeof fields === "string" || Array.isArray(fields)) fields = { + content: fields, + role + }; + super(fields); + this.role = fields.role; + } + static isInstance(obj) { + return super.isInstance(obj) && obj.type === "generic"; + } + get _printableFields() { + return { + ...super._printableFields, + role: this.role + }; + } +}; +/** +* Represents a chunk of a chat message, which can be concatenated with +* other chat message chunks. +*/ +var ChatMessageChunk = class extends BaseMessageChunk { + static lc_name() { + return "ChatMessageChunk"; + } + type = "generic"; + role; + constructor(fields, role) { + if (typeof fields === "string" || Array.isArray(fields)) fields = { + content: fields, + role + }; + super(fields); + this.role = fields.role; + } + concat(chunk) { + const Cls = this.constructor; + return new Cls({ + content: mergeContent(this.content, chunk.content), + additional_kwargs: _mergeDicts(this.additional_kwargs, chunk.additional_kwargs), + response_metadata: _mergeDicts(this.response_metadata, chunk.response_metadata), + role: this.role, + id: this.id ?? chunk.id + }); + } + static isInstance(obj) { + return super.isInstance(obj) && obj.type === "generic"; + } + get _printableFields() { + return { + ...super._printableFields, + role: this.role + }; + } +}; +/** +* @deprecated Use {@link ChatMessage.isInstance} instead +*/ +function isChatMessage(x) { + return x._getType() === "generic"; +} +/** +* @deprecated Use {@link ChatMessageChunk.isInstance} instead +*/ +function isChatMessageChunk(x) { + return x._getType() === "generic"; +} + +//#endregion + +//# sourceMappingURL=chat.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/function.js + + +//#region src/messages/function.ts +/** +* Represents a function message in a conversation. +*/ +var FunctionMessage = class extends BaseMessage { + static lc_name() { + return "FunctionMessage"; + } + type = "function"; + name; + constructor(fields) { + super(fields); + this.name = fields.name; + } +}; +/** +* Represents a chunk of a function message, which can be concatenated +* with other function message chunks. +*/ +var FunctionMessageChunk = class extends BaseMessageChunk { + static lc_name() { + return "FunctionMessageChunk"; + } + type = "function"; + concat(chunk) { + const Cls = this.constructor; + return new Cls({ + content: mergeContent(this.content, chunk.content), + additional_kwargs: _mergeDicts(this.additional_kwargs, chunk.additional_kwargs), + response_metadata: _mergeDicts(this.response_metadata, chunk.response_metadata), + name: this.name ?? "", + id: this.id ?? chunk.id + }); + } +}; +function isFunctionMessage(x) { + return x._getType() === "function"; +} +function isFunctionMessageChunk(x) { + return x._getType() === "function"; +} + +//#endregion + +//# sourceMappingURL=function.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/human.js + + +//#region src/messages/human.ts +/** +* Represents a human message in a conversation. +*/ +var HumanMessage = class extends BaseMessage { + static lc_name() { + return "HumanMessage"; + } + type = "human"; + constructor(fields) { + super(fields); + } + static isInstance(obj) { + return super.isInstance(obj) && obj.type === "human"; + } +}; +/** +* Represents a chunk of a human message, which can be concatenated with +* other human message chunks. +*/ +var HumanMessageChunk = class extends BaseMessageChunk { + static lc_name() { + return "HumanMessageChunk"; + } + type = "human"; + constructor(fields) { + super(fields); + } + concat(chunk) { + const Cls = this.constructor; + return new Cls({ + content: mergeContent(this.content, chunk.content), + additional_kwargs: _mergeDicts(this.additional_kwargs, chunk.additional_kwargs), + response_metadata: _mergeDicts(this.response_metadata, chunk.response_metadata), + id: this.id ?? chunk.id + }); + } + static isInstance(obj) { + return super.isInstance(obj) && obj.type === "human"; + } +}; +/** +* @deprecated Use {@link HumanMessage.isInstance} instead +*/ +function isHumanMessage(x) { + return x.getType() === "human"; +} +/** +* @deprecated Use {@link HumanMessageChunk.isInstance} instead +*/ +function isHumanMessageChunk(x) { + return x.getType() === "human"; +} + +//#endregion + +//# sourceMappingURL=human.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/modifier.js + + +//#region src/messages/modifier.ts +/** +* Message responsible for deleting other messages. +*/ +var RemoveMessage = class extends BaseMessage { + type = "remove"; + /** + * The ID of the message to remove. + */ + id; + constructor(fields) { + super({ + ...fields, + content: [] + }); + this.id = fields.id; + } + get _printableFields() { + return { + ...super._printableFields, + id: this.id + }; + } + static isInstance(obj) { + return super.isInstance(obj) && obj.type === "remove"; + } +}; + +//#endregion + +//# sourceMappingURL=modifier.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/system.js + + +//#region src/messages/system.ts +/** +* Represents a system message in a conversation. +*/ +var SystemMessage = class SystemMessage extends BaseMessage { + static lc_name() { + return "SystemMessage"; + } + type = "system"; + constructor(fields) { + super(fields); + } + /** + * Concatenates a string or another system message with the current system message. + * @param chunk - The chunk to concatenate with the system message. + * @returns A new system message with the concatenated content. + */ + concat(chunk) { + if (typeof chunk === "string") return new SystemMessage({ + ...this, + content: mergeContent(this.content, chunk) + }); + if (SystemMessage.isInstance(chunk)) return new SystemMessage({ + ...this, + additional_kwargs: { + ...this.additional_kwargs, + ...chunk.additional_kwargs + }, + response_metadata: { + ...this.response_metadata, + ...chunk.response_metadata + }, + content: mergeContent(this.content, chunk.content) + }); + throw new Error("Unexpected chunk type for system message"); + } + static isInstance(obj) { + return super.isInstance(obj) && obj.type === "system"; + } +}; +/** +* Represents a chunk of a system message, which can be concatenated with +* other system message chunks. +*/ +var SystemMessageChunk = class extends BaseMessageChunk { + static lc_name() { + return "SystemMessageChunk"; + } + type = "system"; + constructor(fields) { + super(fields); + } + concat(chunk) { + const Cls = this.constructor; + return new Cls({ + content: mergeContent(this.content, chunk.content), + additional_kwargs: _mergeDicts(this.additional_kwargs, chunk.additional_kwargs), + response_metadata: _mergeDicts(this.response_metadata, chunk.response_metadata), + id: this.id ?? chunk.id + }); + } + static isInstance(obj) { + return super.isInstance(obj) && obj.type === "system"; + } +}; +/** +* @deprecated Use {@link SystemMessage.isInstance} instead +*/ +function isSystemMessage(x) { + return x._getType() === "system"; +} +/** +* @deprecated Use {@link SystemMessageChunk.isInstance} instead +*/ +function isSystemMessageChunk(x) { + return x._getType() === "system"; +} + +//#endregion + +//# sourceMappingURL=system.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/block_translators/bedrock_converse.js @@ -39496,7 +40029,7 @@ function getTranslator(modelProvider) { //#region src/messages/metadata.ts function mergeResponseMetadata(a, b) { - const output = _mergeDicts(a ?? {}, b ?? {}); + const output = _mergeDicts(a, b) ?? {}; return output; } function mergeModalitiesTokenDetails(a, b) { @@ -39572,8 +40105,8 @@ var AIMessage = class extends BaseMessage { ].join(" ")); try { if (!(rawToolCalls == null) && toolCalls === void 0) { - const [toolCalls$1, invalidToolCalls] = defaultToolCallParser(rawToolCalls); - initParams.tool_calls = toolCalls$1 ?? []; + const [parsedToolCalls, invalidToolCalls] = defaultToolCallParser(rawToolCalls); + initParams.tool_calls = parsedToolCalls ?? []; initParams.invalid_tool_calls = invalidToolCalls ?? []; } else { initParams.tool_calls = initParams.tool_calls ?? []; @@ -39588,7 +40121,7 @@ var AIMessage = class extends BaseMessage { initParams.content = void 0; } if (initParams.contentBlocks !== void 0) { - initParams.contentBlocks.push(...initParams.tool_calls.map((toolCall) => ({ + if (initParams.tool_calls) initParams.contentBlocks.push(...initParams.tool_calls.map((toolCall) => ({ type: "tool_call", id: toolCall.id, name: toolCall.name, @@ -39623,7 +40156,6 @@ var AIMessage = class extends BaseMessage { if (this.tool_calls) { const missingToolCalls = this.tool_calls.filter((block) => !blocks.some((b) => b.id === block.id && b.name === block.name)); blocks.push(...missingToolCalls.map((block) => ({ - ...block, type: "tool_call", id: block.id, name: block.name, @@ -39682,49 +40214,12 @@ var AIMessageChunk = class extends BaseMessageChunk { usage_metadata: fields.usage_metadata !== void 0 ? fields.usage_metadata : void 0 }; else { - const toolCallChunks = fields.tool_call_chunks ?? []; - const groupedToolCallChunks = toolCallChunks.reduce((acc, chunk) => { - const matchedChunkIndex = acc.findIndex(([match]) => { - if ("id" in chunk && chunk.id && "index" in chunk && chunk.index !== void 0) return chunk.id === match.id && chunk.index === match.index; - if ("id" in chunk && chunk.id) return chunk.id === match.id; - if ("index" in chunk && chunk.index !== void 0) return chunk.index === match.index; - return false; - }); - if (matchedChunkIndex !== -1) acc[matchedChunkIndex].push(chunk); - else acc.push([chunk]); - return acc; - }, []); - const toolCalls = []; - const invalidToolCalls = []; - for (const chunks of groupedToolCallChunks) { - let parsedArgs = null; - const name = chunks[0]?.name ?? ""; - const joinedArgs = chunks.map((c) => c.args || "").join(""); - const argsStr = joinedArgs.length ? joinedArgs : "{}"; - const id = chunks[0]?.id; - try { - parsedArgs = parsePartialJson(argsStr); - if (!id || parsedArgs === null || typeof parsedArgs !== "object" || Array.isArray(parsedArgs)) throw new Error("Malformed tool call chunk args."); - toolCalls.push({ - name, - args: parsedArgs, - id, - type: "tool_call" - }); - } catch { - invalidToolCalls.push({ - name, - args: argsStr, - id, - error: "Malformed args.", - type: "invalid_tool_call" - }); - } - } + const collapsed = collapseToolCallChunks(fields.tool_call_chunks ?? []); initParams = { ...fields, - tool_calls: toolCalls, - invalid_tool_calls: invalidToolCalls, + tool_call_chunks: collapsed.tool_call_chunks, + tool_calls: collapsed.tool_calls, + invalid_tool_calls: collapsed.invalid_tool_calls, usage_metadata: fields.usage_metadata !== void 0 ? fields.usage_metadata : void 0 }; } @@ -39799,355 +40294,6 @@ var AIMessageChunk = class extends BaseMessageChunk { //#endregion //# sourceMappingURL=ai.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/chat.js - - -//#region src/messages/chat.ts -/** -* Represents a chat message in a conversation. -*/ -var ChatMessage = class ChatMessage extends BaseMessage { - static lc_name() { - return "ChatMessage"; - } - type = "generic"; - role; - static _chatMessageClass() { - return ChatMessage; - } - constructor(fields, role) { - if (typeof fields === "string" || Array.isArray(fields)) fields = { - content: fields, - role - }; - super(fields); - this.role = fields.role; - } - static isInstance(obj) { - return super.isInstance(obj) && obj.type === "generic"; - } - get _printableFields() { - return { - ...super._printableFields, - role: this.role - }; - } -}; -/** -* Represents a chunk of a chat message, which can be concatenated with -* other chat message chunks. -*/ -var ChatMessageChunk = class extends BaseMessageChunk { - static lc_name() { - return "ChatMessageChunk"; - } - type = "generic"; - role; - constructor(fields, role) { - if (typeof fields === "string" || Array.isArray(fields)) fields = { - content: fields, - role - }; - super(fields); - this.role = fields.role; - } - concat(chunk) { - const Cls = this.constructor; - return new Cls({ - content: mergeContent(this.content, chunk.content), - additional_kwargs: _mergeDicts(this.additional_kwargs, chunk.additional_kwargs), - response_metadata: _mergeDicts(this.response_metadata, chunk.response_metadata), - role: this.role, - id: this.id ?? chunk.id - }); - } - static isInstance(obj) { - return super.isInstance(obj) && obj.type === "generic"; - } - get _printableFields() { - return { - ...super._printableFields, - role: this.role - }; - } -}; -/** -* @deprecated Use {@link ChatMessage.isInstance} instead -*/ -function isChatMessage(x) { - return x._getType() === "generic"; -} -/** -* @deprecated Use {@link ChatMessageChunk.isInstance} instead -*/ -function isChatMessageChunk(x) { - return x._getType() === "generic"; -} - -//#endregion - -//# sourceMappingURL=chat.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/function.js - - -//#region src/messages/function.ts -/** -* Represents a function message in a conversation. -*/ -var FunctionMessage = class extends BaseMessage { - static lc_name() { - return "FunctionMessage"; - } - type = "function"; - name; - constructor(fields) { - super(fields); - this.name = fields.name; - } -}; -/** -* Represents a chunk of a function message, which can be concatenated -* with other function message chunks. -*/ -var FunctionMessageChunk = class extends BaseMessageChunk { - static lc_name() { - return "FunctionMessageChunk"; - } - type = "function"; - concat(chunk) { - const Cls = this.constructor; - return new Cls({ - content: mergeContent(this.content, chunk.content), - additional_kwargs: _mergeDicts(this.additional_kwargs, chunk.additional_kwargs), - response_metadata: _mergeDicts(this.response_metadata, chunk.response_metadata), - name: this.name ?? "", - id: this.id ?? chunk.id - }); - } -}; -function isFunctionMessage(x) { - return x._getType() === "function"; -} -function isFunctionMessageChunk(x) { - return x._getType() === "function"; -} - -//#endregion - -//# sourceMappingURL=function.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/human.js - - -//#region src/messages/human.ts -/** -* Represents a human message in a conversation. -*/ -var HumanMessage = class extends BaseMessage { - static lc_name() { - return "HumanMessage"; - } - type = "human"; - constructor(fields) { - super(fields); - } - static isInstance(obj) { - return super.isInstance(obj) && obj.type === "human"; - } -}; -/** -* Represents a chunk of a human message, which can be concatenated with -* other human message chunks. -*/ -var HumanMessageChunk = class extends BaseMessageChunk { - static lc_name() { - return "HumanMessageChunk"; - } - type = "human"; - constructor(fields) { - super(fields); - } - concat(chunk) { - const Cls = this.constructor; - return new Cls({ - content: mergeContent(this.content, chunk.content), - additional_kwargs: _mergeDicts(this.additional_kwargs, chunk.additional_kwargs), - response_metadata: _mergeDicts(this.response_metadata, chunk.response_metadata), - id: this.id ?? chunk.id - }); - } - static isInstance(obj) { - return super.isInstance(obj) && obj.type === "human"; - } -}; -/** -* @deprecated Use {@link HumanMessage.isInstance} instead -*/ -function isHumanMessage(x) { - return x.getType() === "human"; -} -/** -* @deprecated Use {@link HumanMessageChunk.isInstance} instead -*/ -function isHumanMessageChunk(x) { - return x.getType() === "human"; -} - -//#endregion - -//# sourceMappingURL=human.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/system.js - - -//#region src/messages/system.ts -/** -* Represents a system message in a conversation. -*/ -var SystemMessage = class SystemMessage extends BaseMessage { - static lc_name() { - return "SystemMessage"; - } - type = "system"; - constructor(fields) { - super(fields); - } - /** - * Concatenates a string or another system message with the current system message. - * @param chunk - The chunk to concatenate with the system message. - * @returns A new system message with the concatenated content. - */ - concat(chunk) { - if (typeof chunk === "string") return new SystemMessage({ - ...this, - content: mergeContent(this.content, chunk) - }); - if (SystemMessage.isInstance(chunk)) return new SystemMessage({ - ...this, - additional_kwargs: { - ...this.additional_kwargs, - ...chunk.additional_kwargs - }, - response_metadata: { - ...this.response_metadata, - ...chunk.response_metadata - }, - content: mergeContent(this.content, chunk.content) - }); - throw new Error("Unexpected chunk type for system message"); - } - static isInstance(obj) { - return super.isInstance(obj) && obj.type === "system"; - } -}; -/** -* Represents a chunk of a system message, which can be concatenated with -* other system message chunks. -*/ -var SystemMessageChunk = class extends BaseMessageChunk { - static lc_name() { - return "SystemMessageChunk"; - } - type = "system"; - constructor(fields) { - super(fields); - } - concat(chunk) { - const Cls = this.constructor; - return new Cls({ - content: mergeContent(this.content, chunk.content), - additional_kwargs: _mergeDicts(this.additional_kwargs, chunk.additional_kwargs), - response_metadata: _mergeDicts(this.response_metadata, chunk.response_metadata), - id: this.id ?? chunk.id - }); - } - static isInstance(obj) { - return super.isInstance(obj) && obj.type === "system"; - } -}; -/** -* @deprecated Use {@link SystemMessage.isInstance} instead -*/ -function isSystemMessage(x) { - return x._getType() === "system"; -} -/** -* @deprecated Use {@link SystemMessageChunk.isInstance} instead -*/ -function isSystemMessageChunk(x) { - return x._getType() === "system"; -} - -//#endregion - -//# sourceMappingURL=system.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/errors/index.js -//#region src/errors/index.ts -function addLangChainErrorFields(error, lc_error_code) { - error.lc_error_code = lc_error_code; - error.message = `${error.message}\n\nTroubleshooting URL: https://docs.langchain.com/oss/javascript/langchain/errors/${lc_error_code}/\n`; - return error; -} - -//#endregion - -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tools/utils.js -//#region src/tools/utils.ts -function _isToolCall(toolCall) { - return !!(toolCall && typeof toolCall === "object" && "type" in toolCall && toolCall.type === "tool_call"); -} -function _configHasToolCallId(config) { - return !!(config && typeof config === "object" && "toolCall" in config && config.toolCall != null && typeof config.toolCall === "object" && "id" in config.toolCall && typeof config.toolCall.id === "string"); -} -/** -* Custom error class used to handle exceptions related to tool input parsing. -* It extends the built-in `Error` class and adds an optional `output` -* property that can hold the output that caused the exception. -*/ -var ToolInputParsingException = class extends Error { - output; - constructor(message, output) { - super(message); - this.output = output; - } -}; - -//#endregion - -//# sourceMappingURL=utils.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/modifier.js - - -//#region src/messages/modifier.ts -/** -* Message responsible for deleting other messages. -*/ -var RemoveMessage = class extends BaseMessage { - type = "remove"; - /** - * The ID of the message to remove. - */ - id; - constructor(fields) { - super({ - ...fields, - content: [] - }); - this.id = fields.id; - } - get _printableFields() { - return { - ...super._printableFields, - id: this.id - }; - } - static isInstance(obj) { - return super.isInstance(obj) && obj.type === "remove"; - } -}; - -//#endregion - -//# sourceMappingURL=modifier.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/utils.js @@ -40160,6 +40306,7 @@ var RemoveMessage = class extends BaseMessage { + //#region src/messages/utils.ts /** * Immediately-invoked function expression. @@ -40250,20 +40397,35 @@ function utils_coerceMessageLikeToMessage(messageLike) { /** * This function is used by memory classes to get a string representation * of the chat message history, based on the message content and role. +* +* Produces compact output like: +* ``` +* Human: What's the weather? +* AI: Let me check...[tool_calls] +* Tool: 72°F and sunny +* ``` +* +* This avoids token inflation from metadata when stringifying message objects directly. */ function getBufferString(messages, humanPrefix = "Human", aiPrefix = "AI") { const string_messages = []; for (const m of messages) { let role; - if (m._getType() === "human") role = humanPrefix; - else if (m._getType() === "ai") role = aiPrefix; - else if (m._getType() === "system") role = "System"; - else if (m._getType() === "tool") role = "Tool"; - else if (m._getType() === "generic") role = m.role; - else throw new Error(`Got unsupported message type: ${m._getType()}`); + if (m.type === "human") role = humanPrefix; + else if (m.type === "ai") role = aiPrefix; + else if (m.type === "system") role = "System"; + else if (m.type === "tool") role = "Tool"; + else if (m.type === "generic") role = m.role; + else throw new Error(`Got unsupported message type: ${m.type}`); const nameStr = m.name ? `${m.name}, ` : ""; - const readableContent = typeof m.content === "string" ? m.content : JSON.stringify(m.content, null, 2); - string_messages.push(`${role}: ${nameStr}${readableContent}`); + const readableContent = m.text; + let message = `${role}: ${nameStr}${readableContent}`; + if (m.type === "ai") { + const aiMessage = m; + if (aiMessage.tool_calls && aiMessage.tool_calls.length > 0) message += JSON.stringify(aiMessage.tool_calls); + else if (aiMessage.additional_kwargs && "function_call" in aiMessage.additional_kwargs) message += JSON.stringify(aiMessage.additional_kwargs.function_call); + } + string_messages.push(message); } return string_messages.join("\n"); } @@ -40347,6 +40509,77 @@ function convertToChunk(message) { else if (ChatMessage.isInstance(message)) return new ChatMessageChunk({ ...message }); else throw new Error("Unknown message type."); } +/** +* Collapses an array of tool call chunks into complete tool calls. +* +* This function groups tool call chunks by their id and/or index, then attempts to +* parse and validate the accumulated arguments for each group. Successfully parsed +* tool calls are returned as valid `ToolCall` objects, while malformed ones are +* returned as `InvalidToolCall` objects. +* +* @param chunks - An array of `ToolCallChunk` objects to collapse +* @returns An object containing: +* - `tool_call_chunks`: The original input chunks +* - `tool_calls`: An array of successfully parsed and validated tool calls +* - `invalid_tool_calls`: An array of tool calls that failed parsing or validation +* +* @remarks +* Chunks are grouped using the following matching logic: +* - If a chunk has both an id and index, it matches chunks with the same id and index +* - If a chunk has only an id, it matches chunks with the same id +* - If a chunk has only an index, it matches chunks with the same index +* +* For each group, the function: +* 1. Concatenates all `args` strings from the chunks +* 2. Attempts to parse the concatenated string as JSON +* 3. Validates that the result is a non-null object with a valid id +* 4. Creates either a `ToolCall` (if valid) or `InvalidToolCall` (if invalid) +*/ +function collapseToolCallChunks(chunks) { + const groupedToolCallChunks = chunks.reduce((acc, chunk) => { + const matchedChunkIndex = acc.findIndex(([match]) => { + if ("id" in chunk && chunk.id && "index" in chunk && chunk.index !== void 0) return chunk.id === match.id && chunk.index === match.index; + if ("id" in chunk && chunk.id) return chunk.id === match.id; + if ("index" in chunk && chunk.index !== void 0) return chunk.index === match.index; + return false; + }); + if (matchedChunkIndex !== -1) acc[matchedChunkIndex].push(chunk); + else acc.push([chunk]); + return acc; + }, []); + const toolCalls = []; + const invalidToolCalls = []; + for (const chunks$1 of groupedToolCallChunks) { + let parsedArgs = null; + const name = chunks$1[0]?.name ?? ""; + const joinedArgs = chunks$1.map((c) => c.args || "").join("").trim(); + const argsStr = joinedArgs.length ? joinedArgs : "{}"; + const id = chunks$1[0]?.id; + try { + parsedArgs = parsePartialJson(argsStr); + if (!id || parsedArgs === null || typeof parsedArgs !== "object" || Array.isArray(parsedArgs)) throw new Error("Malformed tool call chunk args."); + toolCalls.push({ + name, + args: parsedArgs, + id, + type: "tool_call" + }); + } catch { + invalidToolCalls.push({ + name, + args: argsStr, + id, + error: "Malformed args.", + type: "invalid_tool_call" + }); + } + } + return { + tool_call_chunks: chunks, + tool_calls: toolCalls, + invalid_tool_calls: invalidToolCalls + }; +} //#endregion @@ -40520,7 +40753,7 @@ var BaseCallbackHandler = class extends BaseCallbackHandlerMethodsClass { } static fromMethods(methods) { class Handler extends BaseCallbackHandler { - name = v4(); + name = v7(); constructor() { super(); Object.assign(this, methods); @@ -40733,101 +40966,449 @@ function uuid7() { return uuidv7(); } -;// CONCATENATED MODULE: ./node_modules/langsmith/dist/index.js - - - - - -// Update using yarn bump-version -const __version__ = "0.3.82"; +;// CONCATENATED MODULE: external "node:fs" +const external_node_fs_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:fs"); +var external_node_fs_default = /*#__PURE__*/__nccwpck_require__.n(external_node_fs_namespaceObject); +;// CONCATENATED MODULE: external "node:path" +const external_node_path_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:path"); +var external_node_path_default = /*#__PURE__*/__nccwpck_require__.n(external_node_path_namespaceObject); +;// CONCATENATED MODULE: ./node_modules/langsmith/dist/utils/prompts_cache_fs.js +/** + * File system operations for prompt cache (Node.js version). + * + * This file is swapped with prompts_cache_fs.browser.ts for browser builds + * via the package.json browser field. + */ -;// CONCATENATED MODULE: ./node_modules/langsmith/dist/utils/env.js -// Inlined from https://github.com/flexdinesh/browser-or-node -let globalEnv; -const env_isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined"; -const env_isWebWorker = () => typeof globalThis === "object" && - globalThis.constructor && - globalThis.constructor.name === "DedicatedWorkerGlobalScope"; -const env_isJsDom = () => (typeof window !== "undefined" && window.name === "nodejs") || - (typeof navigator !== "undefined" && navigator.userAgent.includes("jsdom")); -// Supabase Edge Function provides a `Deno` global object -// without `version` property -const env_isDeno = () => typeof Deno !== "undefined"; -// Mark not-as-node if in Supabase Edge Function -const env_isNode = () => typeof process !== "undefined" && - typeof process.versions !== "undefined" && - typeof process.versions.node !== "undefined" && - !env_isDeno(); -const env_getEnv = () => { - if (globalEnv) { - return globalEnv; - } - // @ts-expect-error Bun types are not imported due to conflicts with Node types - if (typeof Bun !== "undefined") { - globalEnv = "bun"; - } - else if (env_isBrowser()) { - globalEnv = "browser"; - } - else if (env_isNode()) { - globalEnv = "node"; +/** + * Dump cache entries to a JSON file. + */ +function dumpCache(filePath, entries) { + const dir = external_node_path_namespaceObject.dirname(filePath); + if (!external_node_fs_namespaceObject.existsSync(dir)) { + external_node_fs_namespaceObject.mkdirSync(dir, { recursive: true }); + } + const data = { entries }; + // Atomic write: write to temp file then rename + const tempPath = `${filePath}.tmp`; + try { + external_node_fs_namespaceObject.writeFileSync(tempPath, JSON.stringify(data, null, 2)); + external_node_fs_namespaceObject.renameSync(tempPath, filePath); } - else if (env_isWebWorker()) { - globalEnv = "webworker"; + catch (e) { + // Clean up temp file on failure + if (external_node_fs_namespaceObject.existsSync(tempPath)) { + external_node_fs_namespaceObject.unlinkSync(tempPath); + } + throw e; } - else if (env_isJsDom()) { - globalEnv = "jsdom"; +} +/** + * Load cache entries from a JSON file. + * + * @returns The entries object, or null if file doesn't exist or is invalid. + */ +function loadCache(filePath) { + if (!external_node_fs_namespaceObject.existsSync(filePath)) { + return null; } - else if (env_isDeno()) { - globalEnv = "deno"; + try { + const content = external_node_fs_namespaceObject.readFileSync(filePath, "utf-8"); + const data = JSON.parse(content); + return data.entries ?? null; } - else { - globalEnv = "other"; + catch { + return null; } - return globalEnv; -}; -let env_runtimeEnvironment; -function env_getRuntimeEnvironment() { - if (env_runtimeEnvironment === undefined) { - const env = env_getEnv(); - const releaseEnv = getShas(); - env_runtimeEnvironment = { - library: "langsmith", - runtime: env, - sdk: "langsmith-js", - sdk_version: __version__, - ...releaseEnv, - }; +} + +;// CONCATENATED MODULE: ./node_modules/langsmith/dist/utils/prompts_cache.js +/** + * Prompt caching module for LangSmith SDK. + * + * Provides an LRU cache with background refresh for prompt caching. + * Uses stale-while-revalidate pattern for optimal performance. + * + * Works in all environments. File operations (dump/load) use helpers + * that are swapped for browser builds via package.json browser field. + */ + +/** + * Check if a cache entry is stale based on TTL. + */ +function isStale(entry, ttlSeconds) { + if (ttlSeconds === null) { + return false; // Infinite TTL, never stale } - return env_runtimeEnvironment; + const ageMs = Date.now() - entry.createdAt; + return ageMs > ttlSeconds * 1000; } /** - * Retrieves the LangSmith-specific metadata from the current runtime environment. + * LRU cache with background refresh for prompts. * - * @returns {Record} - * - A record of LangSmith-specific metadata environment variables. + * Features: + * - In-memory LRU cache with configurable max size + * - Background refresh using setInterval + * - Stale-while-revalidate: returns stale data while refresh happens + * - JSON dump/load for offline use + * + * @example + * ```typescript + * const cache = new Cache({ + * maxSize: 100, + * ttlSeconds: 3600, + * fetchFunc: async (key) => client.pullPromptCommit(key), + * }); + * + * // Use the cache + * cache.set("my-prompt:latest", promptCommit); + * const cached = cache.get("my-prompt:latest"); + * + * // Cleanup + * cache.stop(); + * ``` */ -function getLangSmithEnvVarsMetadata() { - const allEnvVars = getLangSmithEnvironmentVariables(); - const envVars = {}; - const excluded = [ - "LANGCHAIN_API_KEY", - "LANGCHAIN_ENDPOINT", - "LANGCHAIN_TRACING_V2", - "LANGCHAIN_PROJECT", - "LANGCHAIN_SESSION", - "LANGSMITH_API_KEY", - "LANGSMITH_ENDPOINT", - "LANGSMITH_TRACING_V2", - "LANGSMITH_PROJECT", - "LANGSMITH_SESSION", - ]; - for (const [key, value] of Object.entries(allEnvVars)) { - if (typeof value === "string" && - !excluded.includes(key) && - !key.toLowerCase().includes("key") && +class Cache { + constructor(config = {}) { + Object.defineProperty(this, "cache", { + enumerable: true, + configurable: true, + writable: true, + value: new Map() + }); + Object.defineProperty(this, "maxSize", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + Object.defineProperty(this, "ttlSeconds", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + Object.defineProperty(this, "refreshIntervalSeconds", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + Object.defineProperty(this, "fetchFunc", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + Object.defineProperty(this, "refreshTimer", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + Object.defineProperty(this, "_metrics", { + enumerable: true, + configurable: true, + writable: true, + value: { + hits: 0, + misses: 0, + refreshes: 0, + refreshErrors: 0, + } + }); + this.maxSize = config.maxSize ?? 100; + this.ttlSeconds = config.ttlSeconds ?? 3600; + this.refreshIntervalSeconds = config.refreshIntervalSeconds ?? 60; + this.fetchFunc = config.fetchFunc; + // Start background refresh if fetch function provided and TTL is set + if (this.fetchFunc && this.ttlSeconds !== null) { + this.startRefreshLoop(); + } + } + /** + * Get cache performance metrics. + */ + get metrics() { + return { ...this._metrics }; + } + /** + * Get total cache requests (hits + misses). + */ + get totalRequests() { + return this._metrics.hits + this._metrics.misses; + } + /** + * Get cache hit rate (0.0 to 1.0). + */ + get hitRate() { + const total = this.totalRequests; + return total > 0 ? this._metrics.hits / total : 0; + } + /** + * Reset all metrics to zero. + */ + resetMetrics() { + this._metrics = { + hits: 0, + misses: 0, + refreshes: 0, + refreshErrors: 0, + }; + } + /** + * Get a value from cache. + * + * Returns the cached value or undefined if not found. + * Stale entries are still returned (background refresh handles updates). + */ + get(key) { + const entry = this.cache.get(key); + if (!entry) { + this._metrics.misses += 1; + return undefined; + } + // Move to end for LRU (delete and re-add) + this.cache.delete(key); + this.cache.set(key, entry); + this._metrics.hits += 1; + return entry.value; + } + /** + * Set a value in the cache. + */ + set(key, value) { + // Check if we need to evict (and key is new) + if (!this.cache.has(key) && this.cache.size >= this.maxSize) { + // Evict oldest (first item in Map) + const oldestKey = this.cache.keys().next().value; + if (oldestKey !== undefined) { + this.cache.delete(oldestKey); + } + } + const entry = { + value, + createdAt: Date.now(), + }; + // Delete first to ensure it's at the end + this.cache.delete(key); + this.cache.set(key, entry); + } + /** + * Remove a specific entry from cache. + */ + invalidate(key) { + this.cache.delete(key); + } + /** + * Clear all cache entries. + */ + clear() { + this.cache.clear(); + } + /** + * Get the number of entries in the cache. + */ + get size() { + return this.cache.size; + } + /** + * Stop background refresh. + * Should be called when the client is being cleaned up. + */ + stop() { + if (this.refreshTimer) { + clearInterval(this.refreshTimer); + this.refreshTimer = undefined; + } + } + /** + * Dump cache contents to a JSON file for offline use. + */ + dump(filePath) { + const entries = {}; + for (const [key, entry] of this.cache.entries()) { + entries[key] = entry.value; + } + dumpCache(filePath, entries); + } + /** + * Load cache contents from a JSON file. + * + * Loaded entries get a fresh TTL starting from load time. + * + * @returns Number of entries loaded. + */ + load(filePath) { + const entries = loadCache(filePath); + if (!entries) { + return 0; + } + let loaded = 0; + const now = Date.now(); + for (const [key, value] of Object.entries(entries)) { + if (this.cache.size >= this.maxSize) { + break; + } + const entry = { + value: value, + createdAt: now, // Fresh TTL from load time + }; + this.cache.set(key, entry); + loaded += 1; + } + return loaded; + } + /** + * Start the background refresh loop. + */ + startRefreshLoop() { + this.refreshTimer = setInterval(() => { + this.refreshStaleEntries().catch((e) => { + // Log but don't die - keep the refresh loop running + console.warn("Unexpected error in cache refresh loop:", e); + }); + }, this.refreshIntervalSeconds * 1000); + // Don't block Node.js from exiting + if (this.refreshTimer.unref) { + this.refreshTimer.unref(); + } + } + /** + * Get list of stale cache keys. + */ + getStaleKeys() { + const staleKeys = []; + for (const [key, entry] of this.cache.entries()) { + if (isStale(entry, this.ttlSeconds)) { + staleKeys.push(key); + } + } + return staleKeys; + } + /** + * Check for stale entries and refresh them. + */ + async refreshStaleEntries() { + if (!this.fetchFunc) { + return; + } + const staleKeys = this.getStaleKeys(); + if (staleKeys.length === 0) { + return; + } + for (const key of staleKeys) { + try { + const newValue = await this.fetchFunc(key); + this.set(key, newValue); + this._metrics.refreshes += 1; + } + catch (e) { + // Keep stale data on refresh failure + this._metrics.refreshErrors += 1; + console.warn(`Failed to refresh cache entry ${key}:`, e); + } + } + } +} + +;// CONCATENATED MODULE: ./node_modules/langsmith/dist/index.js + + + + + + +// Update using yarn bump-version +const __version__ = "0.4.5"; + +;// CONCATENATED MODULE: ./node_modules/langsmith/dist/utils/env.js +// Inlined from https://github.com/flexdinesh/browser-or-node + +let globalEnv; +const env_isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined"; +const env_isWebWorker = () => typeof globalThis === "object" && + globalThis.constructor && + globalThis.constructor.name === "DedicatedWorkerGlobalScope"; +const env_isJsDom = () => (typeof window !== "undefined" && window.name === "nodejs") || + (typeof navigator !== "undefined" && navigator.userAgent.includes("jsdom")); +// Supabase Edge Function provides a `Deno` global object +// without `version` property +const env_isDeno = () => typeof Deno !== "undefined"; +// Mark not-as-node if in Supabase Edge Function +const env_isNode = () => typeof process !== "undefined" && + typeof process.versions !== "undefined" && + typeof process.versions.node !== "undefined" && + !env_isDeno(); +const env_getEnv = () => { + if (globalEnv) { + return globalEnv; + } + // @ts-expect-error Bun types are not imported due to conflicts with Node types + if (typeof Bun !== "undefined") { + globalEnv = "bun"; + } + else if (env_isBrowser()) { + globalEnv = "browser"; + } + else if (env_isNode()) { + globalEnv = "node"; + } + else if (env_isWebWorker()) { + globalEnv = "webworker"; + } + else if (env_isJsDom()) { + globalEnv = "jsdom"; + } + else if (env_isDeno()) { + globalEnv = "deno"; + } + else { + globalEnv = "other"; + } + return globalEnv; +}; +let env_runtimeEnvironment; +function env_getRuntimeEnvironment() { + if (env_runtimeEnvironment === undefined) { + const env = env_getEnv(); + const releaseEnv = getShas(); + env_runtimeEnvironment = { + library: "langsmith", + runtime: env, + sdk: "langsmith-js", + sdk_version: __version__, + ...releaseEnv, + }; + } + return env_runtimeEnvironment; +} +/** + * Retrieves the LangSmith-specific metadata from the current runtime environment. + * + * @returns {Record} + * - A record of LangSmith-specific metadata environment variables. + */ +function getLangSmithEnvVarsMetadata() { + const allEnvVars = getLangSmithEnvironmentVariables(); + const envVars = {}; + const excluded = [ + "LANGCHAIN_API_KEY", + "LANGCHAIN_ENDPOINT", + "LANGCHAIN_TRACING_V2", + "LANGCHAIN_PROJECT", + "LANGCHAIN_SESSION", + "LANGSMITH_API_KEY", + "LANGSMITH_ENDPOINT", + "LANGSMITH_TRACING_V2", + "LANGSMITH_PROJECT", + "LANGSMITH_SESSION", + ]; + for (const [key, value] of Object.entries(allEnvVars)) { + if (typeof value === "string" && + !excluded.includes(key) && + !key.toLowerCase().includes("key") && !key.toLowerCase().includes("secret") && !key.toLowerCase().includes("token")) { if (key === "LANGCHAIN_REVISION_ID") { @@ -42021,6 +42602,33 @@ class LangSmithConflictError extends Error { this.status = 409; } } +/** + * LangSmithNotFoundError + * + * Represents an error that occurs when a requested resource is not found, + * typically corresponding to HTTP 404 status code responses. + * + * @extends Error + */ +class LangSmithNotFoundError extends Error { + constructor(message) { + super(message); + Object.defineProperty(this, "status", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + this.name = "LangSmithNotFoundError"; + this.status = 404; + } +} +function isLangSmithNotFoundError(error) { + return (error != null && + typeof error === "object" && + "name" in error && + error?.name === "LangSmithNotFoundError"); +} /** * Throws an appropriate error based on the response status and body. * @@ -42068,6 +42676,9 @@ async function raiseForStatus(response, context, consumeOnSuccess) { } } const fullMessage = `Failed to ${context}. Received status [${response.status}]: ${response.statusText}. Message: ${errorBody}`; + if (response.status === 404) { + throw new LangSmithNotFoundError(fullMessage); + } if (response.status === 409) { throw new LangSmithConflictError(fullMessage); } @@ -42392,7 +43003,11 @@ function replaceGetterValues(replacer) { -function mergeRuntimeEnvIntoRun(run, cachedEnvVars) { + +function mergeRuntimeEnvIntoRun(run, cachedEnvVars, omitTracedRuntimeInfo) { + if (omitTracedRuntimeInfo) { + return run; + } const runtimeEnv = env_getRuntimeEnvironment(); const envVars = cachedEnvVars ?? getLangSmithEnvVarsMetadata(); const extra = run.extra ?? {}; @@ -42635,6 +43250,12 @@ class Client { writable: true, value: void 0 }); + Object.defineProperty(this, "omitTracedRuntimeInfo", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); Object.defineProperty(this, "tracingSampleRate", { enumerable: true, configurable: true, @@ -42744,12 +43365,24 @@ class Client { writable: true, value: void 0 }); + Object.defineProperty(this, "_cache", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); Object.defineProperty(this, "multipartStreamingDisabled", { enumerable: true, configurable: true, writable: true, value: false }); + Object.defineProperty(this, "_multipartDisabled", { + enumerable: true, + configurable: true, + writable: true, + value: false + }); Object.defineProperty(this, "debug", { enumerable: true, configurable: true, @@ -42795,6 +43428,7 @@ class Client { config.hideInputs ?? config.anonymizer ?? defaultConfig.hideInputs; this.hideOutputs = config.hideOutputs ?? config.anonymizer ?? defaultConfig.hideOutputs; + this.omitTracedRuntimeInfo = config.omitTracedRuntimeInfo ?? false; this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing; this.autoBatchQueue = new AutoBatchQueue(maxMemory); this.blockOnRootRunFinalization = @@ -42808,6 +43442,16 @@ class Client { } // Cache metadata env vars once during construction to avoid repeatedly scanning process.env this.cachedLSEnvVarsForMetadata = getLangSmithEnvVarsMetadata(); + // Initialize cache + if (config.cache === true) { + this._cache = new Cache(); + } + else if (config.cache && typeof config.cache === "object") { + this._cache = config.cache; + } + else { + this._cache = undefined; + } } static getDefaultClientConfig() { const apiKey = getLangSmithEnvironmentVariable("API_KEY"); @@ -43041,7 +43685,7 @@ class Client { async _getBatchSizeLimitBytes() { const serverInfo = await this._ensureServerInfo(); return (this.batchSizeBytesLimit ?? - serverInfo.batch_ingest_config?.size_limit_bytes ?? + serverInfo?.batch_ingest_config?.size_limit_bytes ?? DEFAULT_UNCOMPRESSED_BATCH_SIZE_LIMIT_BYTES); } /** @@ -43050,7 +43694,7 @@ class Client { async _getBatchSizeLimit() { const serverInfo = await this._ensureServerInfo(); return (this.batchSizeLimit ?? - serverInfo.batch_ingest_config?.size_limit ?? + serverInfo?.batch_ingest_config?.size_limit ?? DEFAULT_BATCH_SIZE_LIMIT); } async _getDatasetExamplesMultiPartSupport() { @@ -43113,13 +43757,32 @@ class Client { .map((item) => item.item), }; const serverInfo = await this._ensureServerInfo(); - if (serverInfo?.batch_ingest_config?.use_multipart_endpoint) { + const useMultipart = !this._multipartDisabled && + (serverInfo?.batch_ingest_config?.use_multipart_endpoint ?? true); + if (useMultipart) { const useGzip = serverInfo?.instance_flags?.gzip_body_enabled; - await this.multipartIngestRuns(ingestParams, { - ...options, - useGzip, - sizeBytes: batchSizeBytes, - }); + try { + await this.multipartIngestRuns(ingestParams, { + ...options, + useGzip, + sizeBytes: batchSizeBytes, + }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } + catch (e) { + if (isLangSmithNotFoundError(e)) { + // Fallback to batch ingest if multipart endpoint returns 404 + // Disable multipart for future requests + this._multipartDisabled = true; + await this.batchIngestRuns(ingestParams, { + ...options, + sizeBytes: batchSizeBytes, + }); + } + else { + throw e; + } + } } else { await this.batchIngestRuns(ingestParams, { @@ -43164,7 +43827,7 @@ class Client { async processRunOperation(item) { clearTimeout(this.autoBatchTimeout); this.autoBatchTimeout = undefined; - item.item = mergeRuntimeEnvIntoRun(item.item, this.cachedLSEnvVarsForMetadata); + item.item = mergeRuntimeEnvIntoRun(item.item, this.cachedLSEnvVarsForMetadata, this.omitTracedRuntimeInfo); const itemPromise = this.autoBatchQueue.push(item); if (this.manualFlushMode) { // Rely on manual flushing in serverless environments @@ -43286,7 +43949,7 @@ class Client { }).catch(console.error); return; } - const mergedRunCreateParam = mergeRuntimeEnvIntoRun(runCreate, this.cachedLSEnvVarsForMetadata); + const mergedRunCreateParam = mergeRuntimeEnvIntoRun(runCreate, this.cachedLSEnvVarsForMetadata, this.omitTracedRuntimeInfo); if (options?.apiKey !== undefined) { headers["x-api-key"] = options.apiKey; } @@ -43648,6 +44311,10 @@ class Client { // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (e) { + // Re-throw 404 errors so caller can fall back to batch ingest + if (isLangSmithNotFoundError(e)) { + throw e; + } console.warn(`${e.message.trim()}\n\nContext: ${context}`); } } @@ -45038,6 +45705,49 @@ class Client { return res; }); } + /** + * Delete multiple examples by ID. + * @param exampleIds - The IDs of the examples to delete + * @param options - Optional settings for deletion + * @param options.hardDelete - If true, permanently delete examples. If false (default), soft delete them. + */ + async deleteExamples(exampleIds, options) { + // Validate all UUIDs + exampleIds.forEach((id) => assertUuid(id)); + if (options?.hardDelete) { + // Hard delete uses POST to a different platform endpoint + const path = this._getPlatformEndpointPath("datasets/examples/delete"); + await this.caller.call(async () => { + const res = await this._fetch(`${this.apiUrl}${path}`, { + method: "POST", + headers: { ...this.headers, "Content-Type": "application/json" }, + body: JSON.stringify({ + example_ids: exampleIds, + hard_delete: true, + }), + signal: AbortSignal.timeout(this.timeout_ms), + ...this.fetchOptions, + }); + await raiseForStatus(res, "hard delete examples", true); + return res; + }); + } + else { + // Soft delete uses DELETE with query params + const params = new URLSearchParams(); + exampleIds.forEach((id) => params.append("example_ids", id)); + await this.caller.call(async () => { + const res = await this._fetch(`${this.apiUrl}/examples?${params.toString()}`, { + method: "DELETE", + headers: this.headers, + signal: AbortSignal.timeout(this.timeout_ms), + ...this.fetchOptions, + }); + await raiseForStatus(res, "delete examples", true); + return res; + }); + } + } async updateExample(exampleIdOrUpdate, update) { let exampleId; if (update) { @@ -45185,29 +45895,6 @@ class Client { return res; }); } - /** - * @deprecated This method is deprecated and will be removed in future LangSmith versions, use `evaluate` from `langsmith/evaluation` instead. - */ - async evaluateRun(run, evaluator, { sourceInfo, loadChildRuns, referenceExample, } = { loadChildRuns: false }) { - warn_warnOnce("This method is deprecated and will be removed in future LangSmith versions, use `evaluate` from `langsmith/evaluation` instead."); - let run_; - if (typeof run === "string") { - run_ = await this.readRun(run, { loadChildRuns }); - } - else if (typeof run === "object" && "id" in run) { - run_ = run; - } - else { - throw new Error(`Invalid run type: ${typeof run}`); - } - if (run_.reference_example_id !== null && - run_.reference_example_id !== undefined) { - referenceExample = await this.readExample(run_.reference_example_id); - } - const feedbackResult = await evaluator.evaluateRun(run_, referenceExample); - const [_, feedbacks] = await this._logEvaluationFeedback(feedbackResult, run_, sourceInfo); - return feedbacks[0]; - } async createFeedback(runId, key, { score, value, correction, comment, sourceInfo, feedbackSourceType = "api", sourceRunId, feedbackId, feedbackConfig, projectId, comparativeExperimentId, }) { if (!runId && !projectId) { throw new Error("One of runId or projectId must be provided"); @@ -46068,7 +46755,18 @@ class Client { }); return response.json(); } - async pullPromptCommit(promptIdentifier, options) { + /** + * Generate a cache key for a prompt. + * Format: "{identifier}" or "{identifier}:with_model" + */ + _getPromptCacheKey(promptIdentifier, includeModel) { + const suffix = includeModel ? ":with_model" : ""; + return `${promptIdentifier}${suffix}`; + } + /** + * Fetch a prompt commit directly from the API (bypassing cache). + */ + async _fetchPromptFromApi(promptIdentifier, options) { const [owner, promptName, commitHash] = parsePromptIdentifier(promptIdentifier); const response = await this.caller.call(async () => { const res = await this._fetch(`${this.apiUrl}/commits/${owner}/${promptName}/${commitHash}${options?.includeModel ? "?include_model=true" : ""}`, { @@ -46089,6 +46787,22 @@ class Client { examples: result.examples, }; } + async pullPromptCommit(promptIdentifier, options) { + // Check cache first if not skipped + if (!options?.skipCache && this._cache) { + const cacheKey = this._getPromptCacheKey(promptIdentifier, options?.includeModel); + const cached = this._cache.get(cacheKey); + if (cached) { + return cached; + } + // Cache miss - fetch from API and cache it + const result = await this._fetchPromptFromApi(promptIdentifier, options); + this._cache.set(cacheKey, result); + return result; + } + // No cache or skip cache - fetch directly + return this._fetchPromptFromApi(promptIdentifier, options); + } /** * This method should not be used directly, use `import { pull } from "langchain/hub"` instead. * Using this method directly returns the JSON string of the prompt rather than a LangChain object. @@ -46097,6 +46811,7 @@ class Client { async _pullPrompt(promptIdentifier, options) { const promptObject = await this.pullPromptCommit(promptIdentifier, { includeModel: options?.includeModel, + skipCache: options?.skipCache, }); const prompt = JSON.stringify(promptObject.manifest); return prompt; @@ -46211,6 +46926,22 @@ class Client { throw new Error(`Invalid public ${kind} URL or token: ${urlOrToken}`); } } + /** + * Get the cache instance, if caching is enabled. + * Useful for accessing cache metrics or manually managing the cache. + */ + get cache() { + return this._cache; + } + /** + * Cleanup resources held by the client. + * Stops the cache's background refresh timer. + */ + cleanup() { + if (this._cache) { + this._cache.stop(); + } + } /** * Awaits all pending trace batches. Useful for environments where * you need to be sure that all tracing requests finish before execution ends, @@ -46237,6 +46968,21 @@ class Client { console.warn("[WARNING]: When tracing in manual flush mode, you must call `await client.flush()` manually to submit trace batches."); return Promise.resolve(); } + /** + * traceables use a backgrounded promise before updating runs to avoid blocking + * and to allow waiting for child runs to end. Waiting a small amount of time + * here ensures that they are able to enqueue their run operation before we await + * queued run operations below: + * + * ```ts + * const run = await traceable(async () => { + * return "Hello, world!"; + * }, { client })(); + * + * await client.awaitPendingTraceBatches(); + * ``` + */ + await new Promise((resolve) => setTimeout(resolve, 1)); await Promise.all([ ...this.autoBatchQueue.items.map(({ itemPromise }) => itemPromise), this.batchIngestCaller.queue.onIdle(), @@ -46262,6 +47008,7 @@ const isTracingEnabled = (tracingEnabled) => { ;// CONCATENATED MODULE: ./node_modules/langsmith/dist/singletons/constants.js const _LC_CONTEXT_VARIABLES_KEY = Symbol.for("lc:context_variables"); +const _LC_CHILD_RUN_END_PROMISES_KEY = Symbol.for("lc:child_run_end_promises"); const _REPLICA_TRACE_ROOTS_KEY = Symbol.for("langsmith:replica_trace_roots"); ;// CONCATENATED MODULE: ./node_modules/langsmith/dist/utils/context_vars.js @@ -46571,12 +47318,24 @@ class run_trees_RunTree { writable: true, value: void 0 }); + /** + * @interface + */ Object.defineProperty(this, "_serialized_start_time", { enumerable: true, configurable: true, writable: true, value: void 0 }); + /** + * @internal + */ + Object.defineProperty(this, "_awaitInputsOnPost", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); // If you pass in a run tree directly, return a shallow clone if (run_trees_isRunTree(originalConfig)) { Object.assign(this, { ...originalConfig }); @@ -46934,6 +47693,10 @@ class run_trees_RunTree { }; } async postRun(excludeChildRuns = true) { + // Applies when `processInputs` is an async function + if (this._awaitInputsOnPost) { + this.inputs = await this.inputs; + } try { const runtimeEnv = env_getRuntimeEnvironment(); if (this.replicas && this.replicas.length > 0) { @@ -46966,6 +47729,7 @@ class run_trees_RunTree { await childRun.postRun(false); } } + this.child_runs = []; } catch (error) { console.error(`Error in postRun for run ${this.id}:`, error); @@ -47047,6 +47811,7 @@ class run_trees_RunTree { console.error(`Error in patchRun for run ${this.id}`, error); } } + this.child_runs = []; } toJSON() { return this._convertToCreate(this, undefined, false); @@ -47198,12 +47963,14 @@ function isRunnableConfigLike(x) { // Check that it's an object with a callbacks arg // that has either a CallbackManagerLike object with a langchain tracer within it // or an array with a LangChainTracerLike object within it + const callbacks = x?.callbacks; return (x != null && - typeof x.callbacks === "object" && + typeof callbacks === "object" && // Callback manager with a langchain tracer - (containsLangChainTracerLike(x.callbacks?.handlers) || + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (containsLangChainTracerLike(callbacks?.handlers) || // Or it's an array with a LangChainTracerLike object within it - containsLangChainTracerLike(x.callbacks))); + containsLangChainTracerLike(callbacks))); } function _getWriteReplicasFromEnv() { const envVar = env_getEnvironmentVariable("LANGSMITH_RUNS_ENDPOINTS"); @@ -47359,17 +48126,16 @@ var BaseTracer = class extends BaseCallbackHandler { const { dottedOrder: currentDottedOrder, microsecondPrecisionDatestring } = convertToDottedOrderFormat(new Date(run.start_time).getTime(), run.id, run.execution_order); const storedRun = { ...run }; const parentRun = this.getRunById(storedRun.parent_run_id); - if (storedRun.parent_run_id !== void 0) { - if (parentRun) { - this._addChildRun(parentRun, storedRun); - parentRun.child_execution_order = Math.max(parentRun.child_execution_order, storedRun.child_execution_order); - storedRun.trace_id = parentRun.trace_id; - if (parentRun.dotted_order !== void 0) { - storedRun.dotted_order = [parentRun.dotted_order, currentDottedOrder].join("."); - storedRun._serialized_start_time = microsecondPrecisionDatestring; - } + if (storedRun.parent_run_id !== void 0) if (parentRun) { + this._addChildRun(parentRun, storedRun); + parentRun.child_execution_order = Math.max(parentRun.child_execution_order, storedRun.child_execution_order); + storedRun.trace_id = parentRun.trace_id; + if (parentRun.dotted_order !== void 0) { + storedRun.dotted_order = [parentRun.dotted_order, currentDottedOrder].join("."); + storedRun._serialized_start_time = microsecondPrecisionDatestring; } - } else { + } else storedRun.parent_run_id = void 0; + else { storedRun.trace_id = storedRun.id; storedRun.dotted_order = currentDottedOrder; storedRun._serialized_start_time = microsecondPrecisionDatestring; @@ -47508,7 +48274,7 @@ var BaseTracer = class extends BaseCallbackHandler { * This must sometimes be done synchronously to avoid race conditions * when callbacks are backgrounded, so we expose it as a separate method here. */ - _createRunForChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, name) { + _createRunForChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, name, extra) { const execution_order = this._getExecutionOrder(parentRunId); const start_time = Date.now(); const run = { @@ -47526,7 +48292,10 @@ var BaseTracer = class extends BaseCallbackHandler { child_execution_order: execution_order, run_type: runType ?? "chain", child_runs: [], - extra: metadata ? { metadata } : {}, + extra: metadata ? { + ...extra, + metadata + } : { ...extra }, tags: tags || [] }; return this._addRunToRunMap(run); @@ -48026,9 +48795,22 @@ function isTraceableFunction(x + + //#region src/tracers/tracer_langchain.ts var tracer_langchain_exports = {}; __export(tracer_langchain_exports, { LangChainTracer: () => LangChainTracer }); +/** +* Extract usage_metadata from chat generations. +* +* Iterates through generations to find and aggregates all usage_metadata +* found in chat messages. This is typically present in chat model outputs. +*/ +function _getUsageMetadataFromGenerations(generations) { + let output = void 0; + for (const generationBatch of generations) for (const generation of generationBatch) if (AIMessage.isInstance(generation.message) && generation.message.usage_metadata !== void 0) output = mergeUsageMetadata(output, generation.message.usage_metadata); + return output; +} var LangChainTracer = class LangChainTracer extends BaseTracer { name = "langchain_tracer"; projectName; @@ -48048,12 +48830,27 @@ var LangChainTracer = class LangChainTracer extends BaseTracer { } async persistRun(_run) {} async onRunCreate(run) { - const runTree = this.getRunTreeWithTracingConfig(run.id); - await runTree?.postRun(); + if (!run.extra?.lc_defers_inputs) { + const runTree = this.getRunTreeWithTracingConfig(run.id); + await runTree?.postRun(); + } } async onRunUpdate(run) { const runTree = this.getRunTreeWithTracingConfig(run.id); - await runTree?.patchRun(); + if (run.extra?.lc_defers_inputs) await runTree?.postRun(); + else await runTree?.patchRun(); + } + onLLMEnd(run) { + const outputs = run.outputs; + if (outputs?.generations) { + const usageMetadata = _getUsageMetadataFromGenerations(outputs.generations); + if (usageMetadata !== void 0) { + run.extra = run.extra ?? {}; + const metadata = run.extra.metadata ?? {}; + metadata.usage_metadata = usageMetadata; + run.extra.metadata = metadata; + } + } } getRun(id) { return this.runTreeMap.get(id); @@ -48654,7 +49451,7 @@ var CallbackManager = class CallbackManager extends BaseCallbackManager { } async handleLLMStart(llm, prompts, runId = void 0, _parentRunId = void 0, extraParams = void 0, _tags = void 0, _metadata = void 0, runName = void 0) { return Promise.all(prompts.map(async (prompt, idx) => { - const runId_ = idx === 0 && runId ? runId : v4(); + const runId_ = idx === 0 && runId ? runId : v7(); await Promise.all(this.handlers.map((handler) => { if (handler.ignoreLLM) return; if (isBaseTracer(handler)) handler._createRunForLLMStart(llm, [prompt], runId_, this._parentRunId, extraParams, this.tags, this.metadata, runName); @@ -48673,7 +49470,7 @@ var CallbackManager = class CallbackManager extends BaseCallbackManager { } async handleChatModelStart(llm, messages, runId = void 0, _parentRunId = void 0, extraParams = void 0, _tags = void 0, _metadata = void 0, runName = void 0) { return Promise.all(messages.map(async (messageGroup, idx) => { - const runId_ = idx === 0 && runId ? runId : v4(); + const runId_ = idx === 0 && runId ? runId : v7(); await Promise.all(this.handlers.map((handler) => { if (handler.ignoreLLM) return; if (isBaseTracer(handler)) handler._createRunForChatModelStart(llm, [messageGroup], runId_, this._parentRunId, extraParams, this.tags, this.metadata, runName); @@ -48694,13 +49491,13 @@ var CallbackManager = class CallbackManager extends BaseCallbackManager { return new CallbackManagerForLLMRun(runId_, this.handlers, this.inheritableHandlers, this.tags, this.inheritableTags, this.metadata, this.inheritableMetadata, this._parentRunId); })); } - async handleChainStart(chain, inputs, runId = v4(), runType = void 0, _tags = void 0, _metadata = void 0, runName = void 0) { + async handleChainStart(chain, inputs, runId = v7(), runType = void 0, _tags = void 0, _metadata = void 0, runName = void 0, _parentRunId = void 0, extra = void 0) { await Promise.all(this.handlers.map((handler) => { if (handler.ignoreChain) return; - if (isBaseTracer(handler)) handler._createRunForChainStart(chain, inputs, runId, this._parentRunId, this.tags, this.metadata, runType, runName); + if (isBaseTracer(handler)) handler._createRunForChainStart(chain, inputs, runId, this._parentRunId, this.tags, this.metadata, runType, runName, extra); return consumeCallback(async () => { try { - await handler.handleChainStart?.(chain, inputs, runId, this._parentRunId, this.tags, this.metadata, runType, runName); + await handler.handleChainStart?.(chain, inputs, runId, this._parentRunId, this.tags, this.metadata, runType, runName, extra); } catch (err) { const logFunction = handler.raiseError ? console.error : console.warn; logFunction(`Error in handler ${handler.constructor.name}, handleChainStart: ${err}`); @@ -48710,7 +49507,7 @@ var CallbackManager = class CallbackManager extends BaseCallbackManager { })); return new CallbackManagerForChainRun(runId, this.handlers, this.inheritableHandlers, this.tags, this.inheritableTags, this.metadata, this.inheritableMetadata, this._parentRunId); } - async handleToolStart(tool, input, runId = v4(), _parentRunId = void 0, _tags = void 0, _metadata = void 0, runName = void 0) { + async handleToolStart(tool, input, runId = v7(), _parentRunId = void 0, _tags = void 0, _metadata = void 0, runName = void 0) { await Promise.all(this.handlers.map((handler) => { if (handler.ignoreAgent) return; if (isBaseTracer(handler)) handler._createRunForToolStart(tool, input, runId, this._parentRunId, this.tags, this.metadata, runName); @@ -48726,7 +49523,7 @@ var CallbackManager = class CallbackManager extends BaseCallbackManager { })); return new CallbackManagerForToolRun(runId, this.handlers, this.inheritableHandlers, this.tags, this.inheritableTags, this.metadata, this.inheritableMetadata, this._parentRunId); } - async handleRetrieverStart(retriever, query, runId = v4(), _parentRunId = void 0, _tags = void 0, _metadata = void 0, runName = void 0) { + async handleRetrieverStart(retriever, query, runId = v7(), _parentRunId = void 0, _tags = void 0, _metadata = void 0, runName = void 0) { await Promise.all(this.handlers.map((handler) => { if (handler.ignoreRetriever) return; if (isBaseTracer(handler)) handler._createRunForRetrieverStart(retriever, query, runId, this._parentRunId, this.tags, this.metadata, runName); @@ -48813,7 +49610,7 @@ var CallbackManager = class CallbackManager extends BaseCallbackManager { } static fromHandlers(handlers) { class Handler extends BaseCallbackHandler { - name = v4(); + name = v7(); constructor() { super(); Object.assign(this, handlers); @@ -49367,10 +50164,24 @@ function ensureConfig(config) { } if (empty.timeout !== void 0) { if (empty.timeout <= 0) throw new Error("Timeout must be a positive number"); - const timeoutSignal = AbortSignal.timeout(empty.timeout); + const originalTimeoutMs = empty.timeout; + const timeoutSignal = AbortSignal.timeout(originalTimeoutMs); + if (!empty.metadata) empty.metadata = {}; + if (empty.metadata.timeoutMs === void 0) empty.metadata.timeoutMs = originalTimeoutMs; if (empty.signal !== void 0) { if ("any" in AbortSignal) empty.signal = AbortSignal.any([empty.signal, timeoutSignal]); } else empty.signal = timeoutSignal; + /** + * We are deleting the timeout key for the following reasons: + * - Idempotent normalization: ensureConfig may be called multiple times down the stack. If timeout remains, + * each call would synthesize new timeout signals and combine them, changing the effective timeout unpredictably. + * - Single enforcement path: downstream code relies on signal to enforce cancellation. Leaving timeout means two + * competing mechanisms (numeric timeout and signal) can be applied, sometimes with different semantics. + * - Propagation to children: pickRunnableConfigKeys would keep forwarding timeout to nested runnables, causing + * repeated re-normalization and stacked timeouts. + * - Backward compatibility: a lot of components and tests assume ensureConfig removes timeout post-normalization; + * changing that would be a breaking change. + */ delete empty.timeout; } return empty; @@ -49773,12 +50584,21 @@ __export(core_exports, { }); const JsonPatchError = PatchError; const deepClone = _deepClone; +/** +* Check if a key is a dangerous prototype property that could lead to prototype pollution. +* This provides defense-in-depth alongside the check in applyOperation. +*/ +function isDangerousKey(key) { + return Object.getOwnPropertyNames(Object.prototype).includes(key); +} const objOps = { add: function(obj, key, document) { + if (isDangerousKey(key)) throw new TypeError("JSON-Patch: modifying `__proto__`, `constructor`, or `prototype` prop is banned for security reasons"); obj[key] = this.value; return { newDocument: document }; }, remove: function(obj, key, document) { + if (isDangerousKey(key)) throw new TypeError("JSON-Patch: modifying `__proto__`, `constructor`, or `prototype` prop is banned for security reasons"); var removed = obj[key]; delete obj[key]; return { @@ -49787,6 +50607,7 @@ const objOps = { }; }, replace: function(obj, key, document) { + if (isDangerousKey(key)) throw new TypeError("JSON-Patch: modifying `__proto__`, `constructor`, or `prototype` prop is banned for security reasons"); var removed = obj[key]; obj[key] = this.value; return { @@ -50499,90 +51320,52 @@ var ChatGenerationChunk = class ChatGenerationChunk extends GenerationChunk { //#endregion //# sourceMappingURL=outputs.js.map -;// CONCATENATED MODULE: ./node_modules/is-network-error/index.js +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/is-network-error/index.js +//#region src/utils/is-network-error/index.js const is_network_error_objectToString = Object.prototype.toString; - -const is_network_error_isError = value => is_network_error_objectToString.call(value) === '[object Error]'; - +const is_network_error_isError = (value) => is_network_error_objectToString.call(value) === "[object Error]"; const is_network_error_errorMessages = new Set([ - 'network error', // Chrome - 'Failed to fetch', // Chrome - 'NetworkError when attempting to fetch resource.', // Firefox - 'The Internet connection appears to be offline.', // Safari 16 - 'Network request failed', // `cross-fetch` - 'fetch failed', // Undici (Node.js) - 'terminated', // Undici (Node.js) - ' A network error occurred.', // Bun (WebKit) - 'Network connection lost', // Cloudflare Workers (fetch) + "network error", + "Failed to fetch", + "NetworkError when attempting to fetch resource.", + "The Internet connection appears to be offline.", + "Network request failed", + "fetch failed", + "terminated", + " A network error occurred.", + "Network connection lost" ]); - function is_network_error_isNetworkError(error) { - const isValid = error - && is_network_error_isError(error) - && error.name === 'TypeError' - && typeof error.message === 'string'; - - if (!isValid) { - return false; - } - - const {message, stack} = error; - - // Safari 17+ has generic message but no stack for network errors - if (message === 'Load failed') { - return stack === undefined - // Sentry adds its own stack trace to the fetch error, so also check for that - || '__sentry_captured__' in error; - } - - // Deno network errors start with specific text - if (message.startsWith('error sending request for url')) { - return true; - } - - // Standard network error messages + const isValid = error && is_network_error_isError(error) && error.name === "TypeError" && typeof error.message === "string"; + if (!isValid) return false; + const { message, stack } = error; + if (message === "Load failed") return stack === void 0 || "__sentry_captured__" in error; + if (message.startsWith("error sending request for url")) return true; return is_network_error_errorMessages.has(message); } -;// CONCATENATED MODULE: ./node_modules/p-retry/index.js - - -function p_retry_validateRetries(retries) { - if (typeof retries === 'number') { - if (retries < 0) { - throw new TypeError('Expected `retries` to be a non-negative number.'); - } - - if (Number.isNaN(retries)) { - throw new TypeError('Expected `retries` to be a valid number or Infinity, got NaN.'); - } - } else if (retries !== undefined) { - throw new TypeError('Expected `retries` to be a number or Infinity.'); - } -} - -function p_retry_validateNumberOption(name, value, {min = 0, allowInfinity = false} = {}) { - if (value === undefined) { - return; - } - - if (typeof value !== 'number' || Number.isNaN(value)) { - throw new TypeError(`Expected \`${name}\` to be a number${allowInfinity ? ' or Infinity' : ''}.`); - } +//#endregion - if (!allowInfinity && !Number.isFinite(value)) { - throw new TypeError(`Expected \`${name}\` to be a finite number.`); - } +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/p-retry/index.js - if (value < min) { - throw new TypeError(`Expected \`${name}\` to be \u2265 ${min}.`); - } -} -class p_retry_AbortError extends Error { +//#region src/utils/p-retry/index.js +function p_retry_validateRetries(retries) { + if (typeof retries === "number") { + if (retries < 0) throw new TypeError("Expected `retries` to be a non-negative number."); + if (Number.isNaN(retries)) throw new TypeError("Expected `retries` to be a valid number or Infinity, got NaN."); + } else if (retries !== void 0) throw new TypeError("Expected `retries` to be a number or Infinity."); +} +function p_retry_validateNumberOption(name, value, { min = 0, allowInfinity = false } = {}) { + if (value === void 0) return; + if (typeof value !== "number" || Number.isNaN(value)) throw new TypeError(`Expected \`${name}\` to be a number${allowInfinity ? " or Infinity" : ""}.`); + if (!allowInfinity && !Number.isFinite(value)) throw new TypeError(`Expected \`${name}\` to be a finite number.`); + if (value < min) throw new TypeError(`Expected \`${name}\` to be \u2265 ${min}.`); +} +var p_retry_AbortError = class extends Error { constructor(message) { super(); - if (message instanceof Error) { this.originalError = message; ({message} = message); @@ -50590,159 +51373,105 @@ class p_retry_AbortError extends Error { this.originalError = new Error(message); this.originalError.stack = this.stack; } - - this.name = 'AbortError'; + this.name = "AbortError"; this.message = message; } -} - +}; function p_retry_calculateDelay(retriesConsumed, options) { const attempt = Math.max(1, retriesConsumed + 1); - const random = options.randomize ? (Math.random() + 1) : 1; - - let timeout = Math.round(random * options.minTimeout * (options.factor ** (attempt - 1))); + const random = options.randomize ? Math.random() + 1 : 1; + let timeout = Math.round(random * options.minTimeout * options.factor ** (attempt - 1)); timeout = Math.min(timeout, options.maxTimeout); - return timeout; } - function p_retry_calculateRemainingTime(start, max) { - if (!Number.isFinite(max)) { - return max; - } - + if (!Number.isFinite(max)) return max; return max - (performance.now() - start); } - -async function p_retry_onAttemptFailure({error, attemptNumber, retriesConsumed, startTime, options}) { - const normalizedError = error instanceof Error - ? error - : new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`); - - if (normalizedError instanceof p_retry_AbortError) { - throw normalizedError.originalError; - } - - const retriesLeft = Number.isFinite(options.retries) - ? Math.max(0, options.retries - retriesConsumed) - : options.retries; - +async function p_retry_onAttemptFailure({ error, attemptNumber, retriesConsumed, startTime, options }) { + const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`); + if (normalizedError instanceof p_retry_AbortError) throw normalizedError.originalError; + const retriesLeft = Number.isFinite(options.retries) ? Math.max(0, options.retries - retriesConsumed) : options.retries; const maxRetryTime = options.maxRetryTime ?? Number.POSITIVE_INFINITY; - const context = Object.freeze({ error: normalizedError, attemptNumber, retriesLeft, - retriesConsumed, + retriesConsumed }); - await options.onFailedAttempt(context); - - if (p_retry_calculateRemainingTime(startTime, maxRetryTime) <= 0) { - throw normalizedError; - } - + if (p_retry_calculateRemainingTime(startTime, maxRetryTime) <= 0) throw normalizedError; const consumeRetry = await options.shouldConsumeRetry(context); - const remainingTime = p_retry_calculateRemainingTime(startTime, maxRetryTime); - - if (remainingTime <= 0 || retriesLeft <= 0) { - throw normalizedError; - } - + if (remainingTime <= 0 || retriesLeft <= 0) throw normalizedError; if (normalizedError instanceof TypeError && !is_network_error_isNetworkError(normalizedError)) { - if (consumeRetry) { - throw normalizedError; - } - + if (consumeRetry) throw normalizedError; options.signal?.throwIfAborted(); return false; } - - if (!await options.shouldRetry(context)) { - throw normalizedError; - } - + if (!await options.shouldRetry(context)) throw normalizedError; if (!consumeRetry) { options.signal?.throwIfAborted(); return false; } - const delayTime = p_retry_calculateDelay(retriesConsumed, options); const finalDelay = Math.min(delayTime, remainingTime); - - if (finalDelay > 0) { - await new Promise((resolve, reject) => { - const onAbort = () => { - clearTimeout(timeoutToken); - options.signal?.removeEventListener('abort', onAbort); - reject(options.signal.reason); - }; - - const timeoutToken = setTimeout(() => { - options.signal?.removeEventListener('abort', onAbort); - resolve(); - }, finalDelay); - - if (options.unref) { - timeoutToken.unref?.(); - } - - options.signal?.addEventListener('abort', onAbort, {once: true}); - }); - } - + if (finalDelay > 0) await new Promise((resolve, reject) => { + const onAbort = () => { + clearTimeout(timeoutToken); + options.signal?.removeEventListener("abort", onAbort); + reject(options.signal.reason); + }; + const timeoutToken = setTimeout(() => { + options.signal?.removeEventListener("abort", onAbort); + resolve(); + }, finalDelay); + if (options.unref) timeoutToken.unref?.(); + options.signal?.addEventListener("abort", onAbort, { once: true }); + }); options.signal?.throwIfAborted(); - return true; } - async function p_retry_pRetry(input, options = {}) { - options = {...options}; - + options = { ...options }; p_retry_validateRetries(options.retries); - - if (Object.hasOwn(options, 'forever')) { - throw new Error('The `forever` option is no longer supported. For many use-cases, you can set `retries: Infinity` instead.'); - } - + if (Object.hasOwn(options, "forever")) throw new Error("The `forever` option is no longer supported. For many use-cases, you can set `retries: Infinity` instead."); options.retries ??= 10; options.factor ??= 2; - options.minTimeout ??= 1000; + options.minTimeout ??= 1e3; options.maxTimeout ??= Number.POSITIVE_INFINITY; options.maxRetryTime ??= Number.POSITIVE_INFINITY; options.randomize ??= false; options.onFailedAttempt ??= () => {}; options.shouldRetry ??= () => true; options.shouldConsumeRetry ??= () => true; - - // Validate numeric options and normalize edge cases - p_retry_validateNumberOption('factor', options.factor, {min: 0, allowInfinity: false}); - p_retry_validateNumberOption('minTimeout', options.minTimeout, {min: 0, allowInfinity: false}); - p_retry_validateNumberOption('maxTimeout', options.maxTimeout, {min: 0, allowInfinity: true}); - p_retry_validateNumberOption('maxRetryTime', options.maxRetryTime, {min: 0, allowInfinity: true}); - - // Treat non-positive factor as 1 to avoid zero backoff or negative behavior - if (!(options.factor > 0)) { - options.factor = 1; - } - + p_retry_validateNumberOption("factor", options.factor, { + min: 0, + allowInfinity: false + }); + p_retry_validateNumberOption("minTimeout", options.minTimeout, { + min: 0, + allowInfinity: false + }); + p_retry_validateNumberOption("maxTimeout", options.maxTimeout, { + min: 0, + allowInfinity: true + }); + p_retry_validateNumberOption("maxRetryTime", options.maxRetryTime, { + min: 0, + allowInfinity: true + }); + if (!(options.factor > 0)) options.factor = 1; options.signal?.throwIfAborted(); - let attemptNumber = 0; let retriesConsumed = 0; const startTime = performance.now(); - while (Number.isFinite(options.retries) ? retriesConsumed <= options.retries : true) { attemptNumber++; - try { options.signal?.throwIfAborted(); - const result = await input(attemptNumber); - options.signal?.throwIfAborted(); - return result; } catch (error) { if (await p_retry_onAttemptFailure({ @@ -50750,23 +51479,16 @@ async function p_retry_pRetry(input, options = {}) { attemptNumber, retriesConsumed, startTime, - options, - })) { - retriesConsumed++; - } + options + })) retriesConsumed++; } } - - // Should not reach here, but in case it does, throw an error - throw new Error('Retry attempts exhausted without throwing an error.'); + throw new Error("Retry attempts exhausted without throwing an error."); } -function p_retry_makeRetriable(function_, options) { - return function (...arguments_) { - return p_retry_pRetry(() => function_.apply(this, arguments_), options); - }; -} +//#endregion +//# sourceMappingURL=index.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/async_caller.js @@ -50823,7 +51545,7 @@ var async_caller_AsyncCaller = class { const PQueue = true ? p_queue_dist["default"] : p_queue_dist; this.queue = new PQueue({ concurrency: this.maxConcurrency }); } - call(callable, ...args) { + async call(callable, ...args) { return this.queue.add(() => p_retry_pRetry(() => callable(...args).catch((error) => { if (error instanceof Error) throw error; else throw new Error(error); @@ -50862,30 +51584,21 @@ const NEVER = Object.freeze({ }); function $constructor(name, initializer, params) { function init(inst, def) { - if (!inst._zod) { - Object.defineProperty(inst, "_zod", { - value: { - def, - constr: _, - traits: new Set(), - }, - enumerable: false, - }); - } - if (inst._zod.traits.has(name)) { - return; - } + var _a; + Object.defineProperty(inst, "_zod", { + value: inst._zod ?? {}, + enumerable: false, + }); + (_a = inst._zod).traits ?? (_a.traits = new Set()); inst._zod.traits.add(name); initializer(inst, def); // support prototype modifications - const proto = _.prototype; - const keys = Object.keys(proto); - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - if (!(k in inst)) { - inst[k] = proto[k].bind(inst); - } + for (const k in _.prototype) { + if (!(k in inst)) + Object.defineProperty(inst, k, { value: _.prototype[k].bind(inst) }); } + inst._zod.constr = _; + inst._zod.def = def; } // doesn't work if Parent has a constructor with arguments const Parent = params?.Parent ?? Object; @@ -50920,12 +51633,6 @@ class $ZodAsyncError extends Error { super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`); } } -class $ZodEncodeError extends Error { - constructor(name) { - super(`Encountered unidirectional transform during encode: ${name}`); - this.name = "ZodEncodeError"; - } -} const globalConfig = {}; function config(newConfig) { if (newConfig) @@ -50984,33 +51691,22 @@ function cleanRegex(source) { } function floatSafeRemainder(val, step) { const valDecCount = (val.toString().split(".")[1] || "").length; - const stepString = step.toString(); - let stepDecCount = (stepString.split(".")[1] || "").length; - if (stepDecCount === 0 && /\d?e-\d?/.test(stepString)) { - const match = stepString.match(/\d?e-(\d?)/); - if (match?.[1]) { - stepDecCount = Number.parseInt(match[1]); - } - } + const stepDecCount = (step.toString().split(".")[1] || "").length; const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount; const valInt = Number.parseInt(val.toFixed(decCount).replace(".", "")); const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", "")); return (valInt % stepInt) / 10 ** decCount; } -const EVALUATING = Symbol("evaluating"); function defineLazy(object, key, getter) { - let value = undefined; + const set = false; Object.defineProperty(object, key, { get() { - if (value === EVALUATING) { - // Circular reference detected, return undefined to break the cycle - return undefined; - } - if (value === undefined) { - value = EVALUATING; - value = getter(); + if (!set) { + const value = getter(); + object[key] = value; + return value; } - return value; + throw new Error("cached value already set"); }, set(v) { Object.defineProperty(object, key, { @@ -51022,9 +51718,6 @@ function defineLazy(object, key, getter) { configurable: true, }); } -function objectClone(obj) { - return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); -} function assignProp(target, prop, value) { Object.defineProperty(target, prop, { value, @@ -51033,17 +51726,6 @@ function assignProp(target, prop, value) { configurable: true, }); } -function mergeDefs(...defs) { - const mergedDescriptors = {}; - for (const def of defs) { - const descriptors = Object.getOwnPropertyDescriptors(def); - Object.assign(mergedDescriptors, descriptors); - } - return Object.defineProperties({}, mergedDescriptors); -} -function cloneDef(schema) { - return mergeDefs(schema._zod.def); -} function getElementAtPath(obj, path) { if (!path) return obj; @@ -51071,20 +51753,13 @@ function randomString(length = 10) { function esc(str) { return JSON.stringify(str); } -function slugify(input) { - return input - .toLowerCase() - .trim() - .replace(/[^\w\s-]/g, "") - .replace(/[\s_-]+/g, "-") - .replace(/^-+|-+$/g, ""); -} -const captureStackTrace = ("captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => { }); +const captureStackTrace = Error.captureStackTrace + ? Error.captureStackTrace + : (..._args) => { }; function util_isObject(data) { return typeof data === "object" && data !== null && !Array.isArray(data); } const util_allowsEval = cached(() => { - // @ts-ignore if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) { return false; } @@ -51104,8 +51779,6 @@ function isPlainObject(o) { const ctor = o.constructor; if (ctor === undefined) return true; - if (typeof ctor !== "function") - return true; // modified prototype const prot = ctor.prototype; if (util_isObject(prot) === false) @@ -51116,13 +51789,6 @@ function isPlainObject(o) { } return true; } -function shallowClone(o) { - if (isPlainObject(o)) - return { ...o }; - if (Array.isArray(o)) - return [...o]; - return o; -} function numKeys(data) { let keyCount = 0; for (const key in data) { @@ -51168,7 +51834,6 @@ const getParsedType = (data) => { if (typeof Date !== "undefined" && data instanceof Date) { return "date"; } - // @ts-ignore if (typeof File !== "undefined" && data instanceof File) { return "file"; } @@ -51262,68 +51927,44 @@ const BIGINT_FORMAT_RANGES = { uint64: [/* @__PURE__*/ BigInt(0), /* @__PURE__*/ BigInt("18446744073709551615")], }; function pick(schema, mask) { - const currDef = schema._zod.def; - const def = mergeDefs(schema._zod.def, { - get shape() { - const newShape = {}; - for (const key in mask) { - if (!(key in currDef.shape)) { - throw new Error(`Unrecognized key: "${key}"`); - } - if (!mask[key]) - continue; - newShape[key] = currDef.shape[key]; - } - assignProp(this, "shape", newShape); // self-caching - return newShape; - }, + const newShape = {}; + const currDef = schema._zod.def; //.shape; + for (const key in mask) { + if (!(key in currDef.shape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + // pick key + newShape[key] = currDef.shape[key]; + } + return clone(schema, { + ...schema._zod.def, + shape: newShape, checks: [], }); - return clone(schema, def); } function omit(schema, mask) { - const currDef = schema._zod.def; - const def = mergeDefs(schema._zod.def, { - get shape() { - const newShape = { ...schema._zod.def.shape }; - for (const key in mask) { - if (!(key in currDef.shape)) { - throw new Error(`Unrecognized key: "${key}"`); - } - if (!mask[key]) - continue; - delete newShape[key]; - } - assignProp(this, "shape", newShape); // self-caching - return newShape; - }, + const newShape = { ...schema._zod.def.shape }; + const currDef = schema._zod.def; //.shape; + for (const key in mask) { + if (!(key in currDef.shape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + delete newShape[key]; + } + return clone(schema, { + ...schema._zod.def, + shape: newShape, checks: [], }); - return clone(schema, def); } function extend(schema, shape) { if (!isPlainObject(shape)) { throw new Error("Invalid input to extend: expected a plain object"); } - const checks = schema._zod.def.checks; - const hasChecks = checks && checks.length > 0; - if (hasChecks) { - throw new Error("Object schemas containing refinements cannot be extended. Use `.safeExtend()` instead."); - } - const def = mergeDefs(schema._zod.def, { - get shape() { - const _shape = { ...schema._zod.def.shape, ...shape }; - assignProp(this, "shape", _shape); // self-caching - return _shape; - }, - checks: [], - }); - return clone(schema, def); -} -function safeExtend(schema, shape) { - if (!isPlainObject(shape)) { - throw new Error("Invalid input to safeExtend: expected a plain object"); - } const def = { ...schema._zod.def, get shape() { @@ -51331,106 +51972,95 @@ function safeExtend(schema, shape) { assignProp(this, "shape", _shape); // self-caching return _shape; }, - checks: schema._zod.def.checks, + checks: [], // delete existing checks }; return clone(schema, def); } function merge(a, b) { - const def = mergeDefs(a._zod.def, { + return clone(a, { + ...a._zod.def, get shape() { const _shape = { ...a._zod.def.shape, ...b._zod.def.shape }; assignProp(this, "shape", _shape); // self-caching return _shape; }, - get catchall() { - return b._zod.def.catchall; - }, + catchall: b._zod.def.catchall, checks: [], // delete existing checks }); - return clone(a, def); } function partial(Class, schema, mask) { - const def = mergeDefs(schema._zod.def, { - get shape() { - const oldShape = schema._zod.def.shape; - const shape = { ...oldShape }; - if (mask) { - for (const key in mask) { - if (!(key in oldShape)) { - throw new Error(`Unrecognized key: "${key}"`); - } - if (!mask[key]) - continue; - // if (oldShape[key]!._zod.optin === "optional") continue; - shape[key] = Class - ? new Class({ - type: "optional", - innerType: oldShape[key], - }) - : oldShape[key]; - } - } - else { - for (const key in oldShape) { - // if (oldShape[key]!._zod.optin === "optional") continue; - shape[key] = Class - ? new Class({ - type: "optional", - innerType: oldShape[key], - }) - : oldShape[key]; - } - } - assignProp(this, "shape", shape); // self-caching - return shape; - }, + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) { + for (const key in mask) { + if (!(key in oldShape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + // if (oldShape[key]!._zod.optin === "optional") continue; + shape[key] = Class + ? new Class({ + type: "optional", + innerType: oldShape[key], + }) + : oldShape[key]; + } + } + else { + for (const key in oldShape) { + // if (oldShape[key]!._zod.optin === "optional") continue; + shape[key] = Class + ? new Class({ + type: "optional", + innerType: oldShape[key], + }) + : oldShape[key]; + } + } + return clone(schema, { + ...schema._zod.def, + shape, checks: [], }); - return clone(schema, def); } function required(Class, schema, mask) { - const def = mergeDefs(schema._zod.def, { - get shape() { - const oldShape = schema._zod.def.shape; - const shape = { ...oldShape }; - if (mask) { - for (const key in mask) { - if (!(key in shape)) { - throw new Error(`Unrecognized key: "${key}"`); - } - if (!mask[key]) - continue; - // overwrite with non-optional - shape[key] = new Class({ - type: "nonoptional", - innerType: oldShape[key], - }); - } - } - else { - for (const key in oldShape) { - // overwrite with non-optional - shape[key] = new Class({ - type: "nonoptional", - innerType: oldShape[key], - }); - } - } - assignProp(this, "shape", shape); // self-caching - return shape; - }, + const oldShape = schema._zod.def.shape; + const shape = { ...oldShape }; + if (mask) { + for (const key in mask) { + if (!(key in shape)) { + throw new Error(`Unrecognized key: "${key}"`); + } + if (!mask[key]) + continue; + // overwrite with non-optional + shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key], + }); + } + } + else { + for (const key in oldShape) { + // overwrite with non-optional + shape[key] = new Class({ + type: "nonoptional", + innerType: oldShape[key], + }); + } + } + return clone(schema, { + ...schema._zod.def, + shape, + // optional: [], checks: [], }); - return clone(schema, def); } -// invalid_type | too_big | too_small | invalid_format | not_multiple_of | unrecognized_keys | invalid_union | invalid_key | invalid_element | invalid_value | custom function aborted(x, startIndex = 0) { - if (x.aborted === true) - return true; for (let i = startIndex; i < x.issues.length; i++) { - if (x.issues[i]?.continue !== true) { + if (x.issues[i]?.continue !== true) return true; - } } return false; } @@ -51469,7 +52099,6 @@ function getSizableOrigin(input) { return "set"; if (input instanceof Map) return "map"; - // @ts-ignore if (input instanceof File) return "file"; return "unknown"; @@ -51501,46 +52130,6 @@ function cleanEnum(obj) { }) .map((el) => el[1]); } -// Codec utility functions -function base64ToUint8Array(base64) { - const binaryString = atob(base64); - const bytes = new Uint8Array(binaryString.length); - for (let i = 0; i < binaryString.length; i++) { - bytes[i] = binaryString.charCodeAt(i); - } - return bytes; -} -function uint8ArrayToBase64(bytes) { - let binaryString = ""; - for (let i = 0; i < bytes.length; i++) { - binaryString += String.fromCharCode(bytes[i]); - } - return btoa(binaryString); -} -function base64urlToUint8Array(base64url) { - const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/"); - const padding = "=".repeat((4 - (base64.length % 4)) % 4); - return base64ToUint8Array(base64 + padding); -} -function uint8ArrayToBase64url(bytes) { - return uint8ArrayToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); -} -function hexToUint8Array(hex) { - const cleanHex = hex.replace(/^0x/, ""); - if (cleanHex.length % 2 !== 0) { - throw new Error("Invalid hex string length"); - } - const bytes = new Uint8Array(cleanHex.length / 2); - for (let i = 0; i < cleanHex.length; i += 2) { - bytes[i / 2] = Number.parseInt(cleanHex.slice(i, i + 2), 16); - } - return bytes; -} -function uint8ArrayToHex(bytes) { - return Array.from(bytes) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); -} // instanceof class Class { constructor(..._args) { } @@ -51559,7 +52148,13 @@ const initializer = (inst, def) => { value: def, enumerable: false, }); - inst.message = JSON.stringify(def, jsonStringifyReplacer, 2); + Object.defineProperty(inst, "message", { + get() { + return JSON.stringify(def, jsonStringifyReplacer, 2); + }, + enumerable: true, + // configurable: false, + }); Object.defineProperty(inst, "toString", { value: () => inst.message, enumerable: false, @@ -51581,7 +52176,11 @@ function flattenError(error, mapper = (issue) => issue.message) { } return { formErrors, fieldErrors }; } -function formatError(error, mapper = (issue) => issue.message) { +function formatError(error, _mapper) { + const mapper = _mapper || + function (issue) { + return issue.message; + }; const fieldErrors = { _errors: [] }; const processError = (error) => { for (const issue of error.issues) { @@ -51619,7 +52218,11 @@ function formatError(error, mapper = (issue) => issue.message) { processError(error); return fieldErrors; } -function treeifyError(error, mapper = (issue) => issue.message) { +function treeifyError(error, _mapper) { + const mapper = _mapper || + function (issue) { + return issue.message; + }; const result = { errors: [] }; const processError = (error, path = []) => { var _a, _b; @@ -51698,9 +52301,8 @@ function treeifyError(error, mapper = (issue) => issue.message) { * ✖ Invalid input: expected number * ``` */ -function toDotPath(_path) { +function toDotPath(path) { const segs = []; - const path = _path.map((seg) => (typeof seg === "object" ? seg.key : seg)); for (const seg of path) { if (typeof seg === "number") segs.push(`[${seg}]`); @@ -51719,7 +52321,7 @@ function toDotPath(_path) { function prettifyError(error) { const lines = []; // sort by path length - const issues = [...error.issues].sort((a, b) => (a.path ?? []).length - (b.path ?? []).length); + const issues = [...error.issues].sort((a, b) => a.path.length - b.path.length); // Process each issue for (const issue of issues) { lines.push(`✖ ${issue.message}`); @@ -51788,45 +52390,61 @@ const _safeParseAsync = (_Err) => async (schema, value, _ctx) => { : { success: true, data: result.value }; }; const safeParseAsync = /* @__PURE__*/ _safeParseAsync($ZodRealError); -const _encode = (_Err) => (schema, value, _ctx) => { - const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" }; - return _parse(_Err)(schema, value, ctx); -}; -const encode = /* @__PURE__*/ _encode($ZodRealError); -const _decode = (_Err) => (schema, value, _ctx) => { - return _parse(_Err)(schema, value, _ctx); -}; -const decode = /* @__PURE__*/ _decode($ZodRealError); -const _encodeAsync = (_Err) => async (schema, value, _ctx) => { - const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" }; - return _parseAsync(_Err)(schema, value, ctx); -}; -const encodeAsync = /* @__PURE__*/ _encodeAsync($ZodRealError); -const _decodeAsync = (_Err) => async (schema, value, _ctx) => { - return _parseAsync(_Err)(schema, value, _ctx); -}; -const decodeAsync = /* @__PURE__*/ _decodeAsync($ZodRealError); -const _safeEncode = (_Err) => (schema, value, _ctx) => { - const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" }; - return _safeParse(_Err)(schema, value, ctx); -}; -const safeEncode = /* @__PURE__*/ _safeEncode($ZodRealError); -const _safeDecode = (_Err) => (schema, value, _ctx) => { - return _safeParse(_Err)(schema, value, _ctx); -}; -const safeDecode = /* @__PURE__*/ _safeDecode($ZodRealError); -const _safeEncodeAsync = (_Err) => async (schema, value, _ctx) => { - const ctx = _ctx ? Object.assign(_ctx, { direction: "backward" }) : { direction: "backward" }; - return _safeParseAsync(_Err)(schema, value, ctx); -}; -const safeEncodeAsync = /* @__PURE__*/ _safeEncodeAsync($ZodRealError); -const _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => { - return _safeParseAsync(_Err)(schema, value, _ctx); -}; -const safeDecodeAsync = /* @__PURE__*/ _safeDecodeAsync($ZodRealError); -;// CONCATENATED MODULE: ./node_modules/zod/v4/core/regexes.js +;// CONCATENATED MODULE: ./node_modules/zod/v4/core/registries.js +const $output = Symbol("ZodOutput"); +const $input = Symbol("ZodInput"); +class $ZodRegistry { + constructor() { + this._map = new Map(); + this._idmap = new Map(); + } + add(schema, ..._meta) { + const meta = _meta[0]; + this._map.set(schema, meta); + if (meta && typeof meta === "object" && "id" in meta) { + if (this._idmap.has(meta.id)) { + throw new Error(`ID ${meta.id} already exists in the registry`); + } + this._idmap.set(meta.id, schema); + } + return this; + } + clear() { + this._map = new Map(); + this._idmap = new Map(); + return this; + } + remove(schema) { + const meta = this._map.get(schema); + if (meta && typeof meta === "object" && "id" in meta) { + this._idmap.delete(meta.id); + } + this._map.delete(schema); + return this; + } + get(schema) { + // return this._map.get(schema) as any; + // inherit metadata + const p = schema._zod.parent; + if (p) { + const pm = { ...(this.get(p) ?? {}) }; + delete pm.id; // do not inherit id + return { ...pm, ...this._map.get(schema) }; + } + return this._map.get(schema); + } + has(schema) { + return this._map.has(schema); + } +} +// registries +function registry() { + return new $ZodRegistry(); +} +const globalRegistry = /*@__PURE__*/ registry(); +;// CONCATENATED MODULE: ./node_modules/zod/v4/core/regexes.js const cuid = /^[cC][^\s-]{8,}$/; const cuid2 = /^[0-9a-z]+$/; const ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/; @@ -51839,17 +52457,17 @@ const duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+ const extendedDuration = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/; /** A regex for any UUID-like identifier: 8-4-4-4-12 hex pattern */ const guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/; -/** Returns a regex for validating an RFC 9562/4122 UUID. +/** Returns a regex for validating an RFC 4122 UUID. * * @param version Optionally specify a version 1-8. If no version is specified, all versions are supported. */ const uuid = (version) => { if (!version) - return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/; + return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$/; return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`); }; -const uuid4 = /*@__PURE__*/ uuid(4); -const regexes_uuid6 = /*@__PURE__*/ uuid(6); -const regexes_uuid7 = /*@__PURE__*/ uuid(7); +const uuid4 = /*@__PURE__*/ (/* unused pure expression or super */ null && (uuid(4))); +const regexes_uuid6 = /*@__PURE__*/ (/* unused pure expression or super */ null && (uuid(6))); +const regexes_uuid7 = /*@__PURE__*/ (/* unused pure expression or super */ null && (uuid(7))); /** Practical email validation */ const email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/; /** Equivalent to the HTML5 input[type=email] validation implemented by browsers. Source: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email */ @@ -51858,7 +52476,6 @@ const html5Email = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-] const rfc5322Email = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; /** A loose regex that allows Unicode characters, enforces length limits, and that's about it. */ const unicodeEmail = /^[^\s@"]{1,64}@[^\s@]{1,255}$/u; -const idnEmail = unicodeEmail; const browserEmail = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; // from https://thekevinscott.com/emojis-in-javascript/#writing-a-regular-expression const _emoji = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; @@ -51866,19 +52483,16 @@ function emoji() { return new RegExp(_emoji, "u"); } const ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; -const ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/; -const mac = (delimiter) => { - const escapedDelim = escapeRegex(delimiter ?? ":"); - return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`); -}; +const ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})$/; const cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/; const cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; // https://stackoverflow.com/questions/7860392/determine-if-string-is-in-base64-using-javascript const base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/; const base64url = /^[A-Za-z0-9_-]*$/; // based on https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address -// export const hostname: RegExp = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$/; -const hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/; +// export const hostname: RegExp = +// /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)+([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/; +const hostname = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$/; const domain = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/; // https://blog.stevenlevithan.com/archives/validate-phone-number#r4-3 (regex sans spaces) const e164 = /^\+(?:[0-9]){6,14}[0-9]$/; @@ -51905,9 +52519,8 @@ function datetime(args) { const opts = ["Z"]; if (args.local) opts.push(""); - // if (args.offset) opts.push(`([+-]\\d{2}:\\d{2})`); if (args.offset) - opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`); + opts.push(`([+-]\\d{2}:\\d{2})`); const timeRegex = `${time}(?:${opts.join("|")})`; return new RegExp(`^${dateSource}T(?:${timeRegex})$`); } @@ -51915,49 +52528,18 @@ const string = (params) => { const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; return new RegExp(`^${regex}$`); }; -const bigint = /^-?\d+n?$/; -const integer = /^-?\d+$/; -const number = /^-?\d+(?:\.\d+)?/; -const regexes_boolean = /^(?:true|false)$/i; -const _null = /^null$/i; +const bigint = /^\d+n?$/; +const integer = /^\d+$/; +const number = /^-?\d+(?:\.\d+)?/i; +const regexes_boolean = /true|false/i; +const _null = /null/i; -const _undefined = /^undefined$/i; +const _undefined = /undefined/i; // regex for string with no uppercase letters const lowercase = /^[^A-Z]*$/; // regex for string with no lowercase letters const uppercase = /^[^a-z]*$/; -// regex for hexadecimal strings (any length) -const hex = /^[0-9a-fA-F]*$/; -// Hash regexes for different algorithms and encodings -// Helper function to create base64 regex with exact length and padding -function fixedBase64(bodyLength, padding) { - return new RegExp(`^[A-Za-z0-9+/]{${bodyLength}}${padding}$`); -} -// Helper function to create base64url regex with exact length (no padding) -function fixedBase64url(length) { - return new RegExp(`^[A-Za-z0-9_-]{${length}}$`); -} -// MD5 (16 bytes): base64 = 24 chars total (22 + "==") -const md5_hex = /^[0-9a-fA-F]{32}$/; -const md5_base64 = /*@__PURE__*/ fixedBase64(22, "=="); -const md5_base64url = /*@__PURE__*/ fixedBase64url(22); -// SHA1 (20 bytes): base64 = 28 chars total (27 + "=") -const sha1_hex = /^[0-9a-fA-F]{40}$/; -const sha1_base64 = /*@__PURE__*/ fixedBase64(27, "="); -const sha1_base64url = /*@__PURE__*/ fixedBase64url(27); -// SHA256 (32 bytes): base64 = 44 chars total (43 + "=") -const sha256_hex = /^[0-9a-fA-F]{64}$/; -const sha256_base64 = /*@__PURE__*/ fixedBase64(43, "="); -const sha256_base64url = /*@__PURE__*/ fixedBase64url(43); -// SHA384 (48 bytes): base64 = 64 chars total (no padding) -const sha384_hex = /^[0-9a-fA-F]{96}$/; -const sha384_base64 = /*@__PURE__*/ fixedBase64(64, ""); -const sha384_base64url = /*@__PURE__*/ fixedBase64url(64); -// SHA512 (64 bytes): base64 = 88 chars total (86 + "==") -const sha512_hex = /^[0-9a-fA-F]{128}$/; -const sha512_base64 = /*@__PURE__*/ fixedBase64(86, "=="); -const sha512_base64url = /*@__PURE__*/ fixedBase64url(86); ;// CONCATENATED MODULE: ./node_modules/zod/v4/core/checks.js // import { $ZodType } from "./schemas.js"; @@ -52087,7 +52669,6 @@ const $ZodCheckNumberFormat = /*@__PURE__*/ $constructor("$ZodCheckNumberFormat" expected: origin, format: def.format, code: "invalid_type", - continue: false, input, inst, }); @@ -52151,9 +52732,9 @@ const $ZodCheckNumberFormat = /*@__PURE__*/ $constructor("$ZodCheckNumberFormat" } }; }); -const $ZodCheckBigIntFormat = /*@__PURE__*/ $constructor("$ZodCheckBigIntFormat", (inst, def) => { +const $ZodCheckBigIntFormat = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodCheckBigIntFormat", (inst, def) => { $ZodCheck.init(inst, def); // no format checks - const [minimum, maximum] = BIGINT_FORMAT_RANGES[def.format]; + const [minimum, maximum] = util.BIGINT_FORMAT_RANGES[def.format]; inst._zod.onattach.push((inst) => { const bag = inst._zod.bag; bag.format = def.format; @@ -52183,13 +52764,13 @@ const $ZodCheckBigIntFormat = /*@__PURE__*/ $constructor("$ZodCheckBigIntFormat" }); } }; -}); -const $ZodCheckMaxSize = /*@__PURE__*/ $constructor("$ZodCheckMaxSize", (inst, def) => { +}))); +const $ZodCheckMaxSize = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodCheckMaxSize", (inst, def) => { var _a; $ZodCheck.init(inst, def); (_a = inst._zod.def).when ?? (_a.when = (payload) => { const val = payload.value; - return !nullish(val) && val.size !== undefined; + return !util.nullish(val) && val.size !== undefined; }); inst._zod.onattach.push((inst) => { const curr = (inst._zod.bag.maximum ?? Number.POSITIVE_INFINITY); @@ -52202,22 +52783,21 @@ const $ZodCheckMaxSize = /*@__PURE__*/ $constructor("$ZodCheckMaxSize", (inst, d if (size <= def.maximum) return; payload.issues.push({ - origin: getSizableOrigin(input), + origin: util.getSizableOrigin(input), code: "too_big", maximum: def.maximum, - inclusive: true, input, inst, continue: !def.abort, }); }; -}); -const $ZodCheckMinSize = /*@__PURE__*/ $constructor("$ZodCheckMinSize", (inst, def) => { +}))); +const $ZodCheckMinSize = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodCheckMinSize", (inst, def) => { var _a; $ZodCheck.init(inst, def); (_a = inst._zod.def).when ?? (_a.when = (payload) => { const val = payload.value; - return !nullish(val) && val.size !== undefined; + return !util.nullish(val) && val.size !== undefined; }); inst._zod.onattach.push((inst) => { const curr = (inst._zod.bag.minimum ?? Number.NEGATIVE_INFINITY); @@ -52230,22 +52810,21 @@ const $ZodCheckMinSize = /*@__PURE__*/ $constructor("$ZodCheckMinSize", (inst, d if (size >= def.minimum) return; payload.issues.push({ - origin: getSizableOrigin(input), + origin: util.getSizableOrigin(input), code: "too_small", minimum: def.minimum, - inclusive: true, input, inst, continue: !def.abort, }); }; -}); -const $ZodCheckSizeEquals = /*@__PURE__*/ $constructor("$ZodCheckSizeEquals", (inst, def) => { +}))); +const $ZodCheckSizeEquals = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodCheckSizeEquals", (inst, def) => { var _a; $ZodCheck.init(inst, def); (_a = inst._zod.def).when ?? (_a.when = (payload) => { const val = payload.value; - return !nullish(val) && val.size !== undefined; + return !util.nullish(val) && val.size !== undefined; }); inst._zod.onattach.push((inst) => { const bag = inst._zod.bag; @@ -52260,7 +52839,7 @@ const $ZodCheckSizeEquals = /*@__PURE__*/ $constructor("$ZodCheckSizeEquals", (i return; const tooBig = size > def.size; payload.issues.push({ - origin: getSizableOrigin(input), + origin: util.getSizableOrigin(input), ...(tooBig ? { code: "too_big", maximum: def.size } : { code: "too_small", minimum: def.size }), inclusive: true, exact: true, @@ -52269,7 +52848,7 @@ const $ZodCheckSizeEquals = /*@__PURE__*/ $constructor("$ZodCheckSizeEquals", (i continue: !def.abort, }); }; -}); +}))); const $ZodCheckMaxLength = /*@__PURE__*/ $constructor("$ZodCheckMaxLength", (inst, def) => { var _a; $ZodCheck.init(inst, def); @@ -52488,10 +53067,10 @@ const $ZodCheckEndsWith = /*@__PURE__*/ $constructor("$ZodCheckEndsWith", (inst, /////////////////////////////////// function handleCheckPropertyResult(result, payload, property) { if (result.issues.length) { - payload.issues.push(...prefixIssues(property, result.issues)); + payload.issues.push(...util.prefixIssues(property, result.issues)); } } -const $ZodCheckProperty = /*@__PURE__*/ $constructor("$ZodCheckProperty", (inst, def) => { +const $ZodCheckProperty = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodCheckProperty", (inst, def) => { $ZodCheck.init(inst, def); inst._zod.check = (payload) => { const result = def.schema._zod.run({ @@ -52504,8 +53083,8 @@ const $ZodCheckProperty = /*@__PURE__*/ $constructor("$ZodCheckProperty", (inst, handleCheckPropertyResult(result, payload, def.property); return; }; -}); -const $ZodCheckMimeType = /*@__PURE__*/ $constructor("$ZodCheckMimeType", (inst, def) => { +}))); +const $ZodCheckMimeType = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodCheckMimeType", (inst, def) => { $ZodCheck.init(inst, def); const mimeSet = new Set(def.mime); inst._zod.onattach.push((inst) => { @@ -52519,10 +53098,9 @@ const $ZodCheckMimeType = /*@__PURE__*/ $constructor("$ZodCheckMimeType", (inst, values: def.mime, input: payload.value.type, inst, - continue: !def.abort, }); }; -}); +}))); const $ZodCheckOverwrite = /*@__PURE__*/ $constructor("$ZodCheckOverwrite", (inst, def) => { $ZodCheck.init(inst, def); inst._zod.check = (payload) => { @@ -52570,8 +53148,8 @@ class Doc { ;// CONCATENATED MODULE: ./node_modules/zod/v4/core/versions.js const versions_version = { major: 4, - minor: 1, - patch: 13, + minor: 0, + patch: 0, }; ;// CONCATENATED MODULE: ./node_modules/zod/v4/core/schemas.js @@ -52593,6 +53171,7 @@ const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => { if (inst._zod.traits.has("$ZodCheck")) { checks.unshift(inst); } + // for (const ch of checks) { for (const fn of ch._zod.onattach) { fn(inst); @@ -52649,47 +53228,7 @@ const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => { } return payload; }; - // const handleChecksResult = ( - // checkResult: ParsePayload, - // originalResult: ParsePayload, - // ctx: ParseContextInternal - // ): util.MaybeAsync => { - // // if the checks mutated the value && there are no issues, re-parse the result - // if (checkResult.value !== originalResult.value && !checkResult.issues.length) - // return inst._zod.parse(checkResult, ctx); - // return originalResult; - // }; - const handleCanaryResult = (canary, payload, ctx) => { - // abort if the canary is aborted - if (aborted(canary)) { - canary.aborted = true; - return canary; - } - // run checks first, then - const checkResult = runChecks(payload, checks, ctx); - if (checkResult instanceof Promise) { - if (ctx.async === false) - throw new $ZodAsyncError(); - return checkResult.then((checkResult) => inst._zod.parse(checkResult, ctx)); - } - return inst._zod.parse(checkResult, ctx); - }; inst._zod.run = (payload, ctx) => { - if (ctx.skipChecks) { - return inst._zod.parse(payload, ctx); - } - if (ctx.direction === "backward") { - // run canary - // initial pass (no checks) - const canary = inst._zod.parse({ value: payload.value, issues: [] }, { ...ctx, skipChecks: true }); - if (canary instanceof Promise) { - return canary.then((canary) => { - return handleCanaryResult(canary, payload, ctx); - }); - } - return handleCanaryResult(canary, payload, ctx); - } - // forward const result = inst._zod.parse(payload, ctx); if (result instanceof Promise) { if (ctx.async === false) @@ -52772,10 +53311,9 @@ const $ZodURL = /*@__PURE__*/ $constructor("$ZodURL", (inst, def) => { $ZodStringFormat.init(inst, def); inst._zod.check = (payload) => { try { - // Trim whitespace from input - const trimmed = payload.value.trim(); - // @ts-ignore - const url = new URL(trimmed); + const orig = payload.value; + const url = new URL(orig); + const href = url.href; if (def.hostname) { def.hostname.lastIndex = 0; if (!def.hostname.test(url.hostname)) { @@ -52783,7 +53321,7 @@ const $ZodURL = /*@__PURE__*/ $constructor("$ZodURL", (inst, def) => { code: "invalid_format", format: "url", note: "Invalid hostname", - pattern: def.hostname.source, + pattern: hostname.source, input: payload.value, inst, continue: !def.abort, @@ -52804,14 +53342,12 @@ const $ZodURL = /*@__PURE__*/ $constructor("$ZodURL", (inst, def) => { }); } } - // Set the output value based on normalize flag - if (def.normalize) { - // Use normalized URL - payload.value = url.href; + // payload.value = url.href; + if (!orig.endsWith("/") && href.endsWith("/")) { + payload.value = href.slice(0, -1); } else { - // Preserve the original input (trimmed) - payload.value = trimmed; + payload.value = href; } return; } @@ -52873,15 +53409,20 @@ const $ZodISODuration = /*@__PURE__*/ $constructor("$ZodISODuration", (inst, def const $ZodIPv4 = /*@__PURE__*/ $constructor("$ZodIPv4", (inst, def) => { def.pattern ?? (def.pattern = ipv4); $ZodStringFormat.init(inst, def); - inst._zod.bag.format = `ipv4`; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = `ipv4`; + }); }); const $ZodIPv6 = /*@__PURE__*/ $constructor("$ZodIPv6", (inst, def) => { def.pattern ?? (def.pattern = ipv6); $ZodStringFormat.init(inst, def); - inst._zod.bag.format = `ipv6`; + inst._zod.onattach.push((inst) => { + const bag = inst._zod.bag; + bag.format = `ipv6`; + }); inst._zod.check = (payload) => { try { - // @ts-ignore new URL(`http://[${payload.value}]`); // return; } @@ -52896,11 +53437,6 @@ const $ZodIPv6 = /*@__PURE__*/ $constructor("$ZodIPv6", (inst, def) => { } }; }); -const $ZodMAC = /*@__PURE__*/ $constructor("$ZodMAC", (inst, def) => { - def.pattern ?? (def.pattern = mac(def.delimiter)); - $ZodStringFormat.init(inst, def); - inst._zod.bag.format = `mac`; -}); const $ZodCIDRv4 = /*@__PURE__*/ $constructor("$ZodCIDRv4", (inst, def) => { def.pattern ?? (def.pattern = cidrv4); $ZodStringFormat.init(inst, def); @@ -52909,11 +53445,8 @@ const $ZodCIDRv6 = /*@__PURE__*/ $constructor("$ZodCIDRv6", (inst, def) => { def.pattern ?? (def.pattern = cidrv6); // not used for validation $ZodStringFormat.init(inst, def); inst._zod.check = (payload) => { - const parts = payload.value.split("/"); + const [address, prefix] = payload.value.split("/"); try { - if (parts.length !== 2) - throw new Error(); - const [address, prefix] = parts; if (!prefix) throw new Error(); const prefixNum = Number(prefix); @@ -52921,7 +53454,6 @@ const $ZodCIDRv6 = /*@__PURE__*/ $constructor("$ZodCIDRv6", (inst, def) => { throw new Error(); if (prefixNum < 0 || prefixNum > 128) throw new Error(); - // @ts-ignore new URL(`http://[${address}]`); } catch { @@ -52942,7 +53474,6 @@ function isValidBase64(data) { if (data.length % 4 !== 0) return false; try { - // @ts-ignore atob(data); return true; } @@ -52953,7 +53484,9 @@ function isValidBase64(data) { const $ZodBase64 = /*@__PURE__*/ $constructor("$ZodBase64", (inst, def) => { def.pattern ?? (def.pattern = base64); $ZodStringFormat.init(inst, def); - inst._zod.bag.contentEncoding = "base64"; + inst._zod.onattach.push((inst) => { + inst._zod.bag.contentEncoding = "base64"; + }); inst._zod.check = (payload) => { if (isValidBase64(payload.value)) return; @@ -52977,7 +53510,9 @@ function isValidBase64URL(data) { const $ZodBase64URL = /*@__PURE__*/ $constructor("$ZodBase64URL", (inst, def) => { def.pattern ?? (def.pattern = base64url); $ZodStringFormat.init(inst, def); - inst._zod.bag.contentEncoding = "base64url"; + inst._zod.onattach.push((inst) => { + inst._zod.bag.contentEncoding = "base64url"; + }); inst._zod.check = (payload) => { if (isValidBase64URL(payload.value)) return; @@ -53003,7 +53538,6 @@ function isValidJWT(token, algorithm = null) { const [header] = tokensParts; if (!header) return false; - // @ts-ignore const parsedHeader = JSON.parse(atob(header)); if ("typ" in parsedHeader && parsedHeader?.typ !== "JWT") return false; @@ -53031,7 +53565,7 @@ const $ZodJWT = /*@__PURE__*/ $constructor("$ZodJWT", (inst, def) => { }); }; }); -const $ZodCustomStringFormat = /*@__PURE__*/ $constructor("$ZodCustomStringFormat", (inst, def) => { +const $ZodCustomStringFormat = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodCustomStringFormat", (inst, def) => { $ZodStringFormat.init(inst, def); inst._zod.check = (payload) => { if (def.fn(payload.value)) @@ -53044,7 +53578,7 @@ const $ZodCustomStringFormat = /*@__PURE__*/ $constructor("$ZodCustomStringForma continue: !def.abort, }); }; -}); +}))); const $ZodNumber = /*@__PURE__*/ $constructor("$ZodNumber", (inst, def) => { $ZodType.init(inst, def); inst._zod.pattern = inst._zod.bag.pattern ?? number; @@ -53075,9 +53609,9 @@ const $ZodNumber = /*@__PURE__*/ $constructor("$ZodNumber", (inst, def) => { return payload; }; }); -const $ZodNumberFormat = /*@__PURE__*/ $constructor("$ZodNumberFormat", (inst, def) => { +const $ZodNumberFormat = /*@__PURE__*/ $constructor("$ZodNumber", (inst, def) => { $ZodCheckNumberFormat.init(inst, def); - $ZodNumber.init(inst, def); // no format checks + $ZodNumber.init(inst, def); // no format checksp }); const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => { $ZodType.init(inst, def); @@ -53100,9 +53634,9 @@ const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => { return payload; }; }); -const $ZodBigInt = /*@__PURE__*/ $constructor("$ZodBigInt", (inst, def) => { +const $ZodBigInt = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodBigInt", (inst, def) => { $ZodType.init(inst, def); - inst._zod.pattern = bigint; + inst._zod.pattern = regexes.bigint; inst._zod.parse = (payload, _ctx) => { if (def.coerce) try { @@ -53119,12 +53653,12 @@ const $ZodBigInt = /*@__PURE__*/ $constructor("$ZodBigInt", (inst, def) => { }); return payload; }; -}); -const $ZodBigIntFormat = /*@__PURE__*/ $constructor("$ZodBigIntFormat", (inst, def) => { - $ZodCheckBigIntFormat.init(inst, def); +}))); +const $ZodBigIntFormat = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodBigInt", (inst, def) => { + checks.$ZodCheckBigIntFormat.init(inst, def); $ZodBigInt.init(inst, def); // no format checks -}); -const $ZodSymbol = /*@__PURE__*/ $constructor("$ZodSymbol", (inst, def) => { +}))); +const $ZodSymbol = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodSymbol", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload, _ctx) => { const input = payload.value; @@ -53138,10 +53672,10 @@ const $ZodSymbol = /*@__PURE__*/ $constructor("$ZodSymbol", (inst, def) => { }); return payload; }; -}); -const $ZodUndefined = /*@__PURE__*/ $constructor("$ZodUndefined", (inst, def) => { +}))); +const $ZodUndefined = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodUndefined", (inst, def) => { $ZodType.init(inst, def); - inst._zod.pattern = _undefined; + inst._zod.pattern = regexes.undefined; inst._zod.values = new Set([undefined]); inst._zod.optin = "optional"; inst._zod.optout = "optional"; @@ -53157,10 +53691,10 @@ const $ZodUndefined = /*@__PURE__*/ $constructor("$ZodUndefined", (inst, def) => }); return payload; }; -}); -const $ZodNull = /*@__PURE__*/ $constructor("$ZodNull", (inst, def) => { +}))); +const $ZodNull = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodNull", (inst, def) => { $ZodType.init(inst, def); - inst._zod.pattern = _null; + inst._zod.pattern = regexes.null; inst._zod.values = new Set([null]); inst._zod.parse = (payload, _ctx) => { const input = payload.value; @@ -53174,7 +53708,7 @@ const $ZodNull = /*@__PURE__*/ $constructor("$ZodNull", (inst, def) => { }); return payload; }; -}); +}))); const $ZodAny = /*@__PURE__*/ $constructor("$ZodAny", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload) => payload; @@ -53195,7 +53729,7 @@ const $ZodNever = /*@__PURE__*/ $constructor("$ZodNever", (inst, def) => { return payload; }; }); -const $ZodVoid = /*@__PURE__*/ $constructor("$ZodVoid", (inst, def) => { +const $ZodVoid = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodVoid", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload, _ctx) => { const input = payload.value; @@ -53209,8 +53743,8 @@ const $ZodVoid = /*@__PURE__*/ $constructor("$ZodVoid", (inst, def) => { }); return payload; }; -}); -const $ZodDate = /*@__PURE__*/ $constructor("$ZodDate", (inst, def) => { +}))); +const $ZodDate = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodDate", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload, _ctx) => { if (def.coerce) { @@ -53233,7 +53767,7 @@ const $ZodDate = /*@__PURE__*/ $constructor("$ZodDate", (inst, def) => { }); return payload; }; -}); +}))); function handleArrayResult(result, final, index) { if (result.issues.length) { final.issues.push(...prefixIssues(index, result.issues)); @@ -53274,88 +53808,58 @@ const $ZodArray = /*@__PURE__*/ $constructor("$ZodArray", (inst, def) => { return payload; //handleArrayResultsAsync(parseResults, final); }; }); -function handlePropertyResult(result, final, key, input) { +function handleObjectResult(result, final, key) { + // if(isOptional) if (result.issues.length) { final.issues.push(...prefixIssues(key, result.issues)); } - if (result.value === undefined) { - if (key in input) { - final.value[key] = undefined; - } - } - else { - final.value[key] = result.value; - } -} -function normalizeDef(def) { - const keys = Object.keys(def.shape); - for (const k of keys) { - if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) { - throw new Error(`Invalid element at key "${k}": expected a Zod schema`); - } - } - const okeys = optionalKeys(def.shape); - return { - ...def, - keys, - keySet: new Set(keys), - numKeys: keys.length, - optionalKeys: new Set(okeys), - }; + final.value[key] = result.value; } -function handleCatchall(proms, input, payload, ctx, def, inst) { - const unrecognized = []; - // iterate over input keys - const keySet = def.keySet; - const _catchall = def.catchall._zod; - const t = _catchall.def.type; - for (const key in input) { - if (keySet.has(key)) - continue; - if (t === "never") { - unrecognized.push(key); - continue; - } - const r = _catchall.run({ value: input[key], issues: [] }, ctx); - if (r instanceof Promise) { - proms.push(r.then((r) => handlePropertyResult(r, payload, key, input))); +function handleOptionalObjectResult(result, final, key, input) { + if (result.issues.length) { + // validation failed against value schema + if (input[key] === undefined) { + // if input was undefined, ignore the error + if (key in input) { + final.value[key] = undefined; + } + else { + final.value[key] = result.value; + } } else { - handlePropertyResult(r, payload, key, input); + final.issues.push(...prefixIssues(key, result.issues)); } } - if (unrecognized.length) { - payload.issues.push({ - code: "unrecognized_keys", - keys: unrecognized, - input, - inst, - }); + else if (result.value === undefined) { + // validation returned `undefined` + if (key in input) + final.value[key] = undefined; + } + else { + // non-undefined value + final.value[key] = result.value; } - if (!proms.length) - return payload; - return Promise.all(proms).then(() => { - return payload; - }); } const $ZodObject = /*@__PURE__*/ $constructor("$ZodObject", (inst, def) => { // requires cast because technically $ZodObject doesn't extend $ZodType.init(inst, def); - // const sh = def.shape; - const desc = Object.getOwnPropertyDescriptor(def, "shape"); - if (!desc?.get) { - const sh = def.shape; - Object.defineProperty(def, "shape", { - get: () => { - const newSh = { ...sh }; - Object.defineProperty(def, "shape", { - value: newSh, - }); - return newSh; - }, - }); - } - const _normalized = cached(() => normalizeDef(def)); + const _normalized = cached(() => { + const keys = Object.keys(def.shape); + for (const k of keys) { + if (!(def.shape[k] instanceof $ZodType)) { + throw new Error(`Invalid element at key "${k}": expected a Zod schema`); + } + } + const okeys = optionalKeys(def.shape); + return { + shape: def.shape, + keys, + keySet: new Set(keys), + numKeys: keys.length, + optionalKeys: new Set(okeys), + }; + }); defineLazy(inst._zod, "propValues", () => { const shape = def.shape; const propValues = {}; @@ -53369,45 +53873,6 @@ const $ZodObject = /*@__PURE__*/ $constructor("$ZodObject", (inst, def) => { } return propValues; }); - const isObject = util_isObject; - const catchall = def.catchall; - let value; - inst._zod.parse = (payload, ctx) => { - value ?? (value = _normalized.value); - const input = payload.value; - if (!isObject(input)) { - payload.issues.push({ - expected: "object", - code: "invalid_type", - input, - inst, - }); - return payload; - } - payload.value = {}; - const proms = []; - const shape = value.shape; - for (const key of value.keys) { - const el = shape[key]; - const r = el._zod.run({ value: input[key], issues: [] }, ctx); - if (r instanceof Promise) { - proms.push(r.then((r) => handlePropertyResult(r, payload, key, input))); - } - else { - handlePropertyResult(r, payload, key, input); - } - } - if (!catchall) { - return proms.length ? Promise.all(proms).then(() => payload) : payload; - } - return handleCatchall(proms, input, payload, ctx, _normalized.value, inst); - }; -}); -const $ZodObjectJIT = /*@__PURE__*/ $constructor("$ZodObjectJIT", (inst, def) => { - // requires cast because technically $ZodObject doesn't extend - $ZodObject.init(inst, def); - const superParse = inst._zod.parse; - const _normalized = cached(() => normalizeDef(def)); const generateFastpass = (shape) => { const doc = new Doc(["shape", "payload", "ctx"]); const normalized = _normalized.value; @@ -53422,29 +53887,44 @@ const $ZodObjectJIT = /*@__PURE__*/ $constructor("$ZodObjectJIT", (inst, def) => ids[key] = `key_${counter++}`; } // A: preserve key order { - doc.write(`const newResult = {};`); + doc.write(`const newResult = {}`); for (const key of normalized.keys) { - const id = ids[key]; - const k = esc(key); - doc.write(`const ${id} = ${parseStr(key)};`); - doc.write(` + if (normalized.optionalKeys.has(key)) { + const id = ids[key]; + doc.write(`const ${id} = ${parseStr(key)};`); + const k = esc(key); + doc.write(` if (${id}.issues.length) { - payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ - ...iss, - path: iss.path ? [${k}, ...iss.path] : [${k}] - }))); - } - - - if (${id}.value === undefined) { - if (${k} in input) { - newResult[${k}] = undefined; + if (input[${k}] === undefined) { + if (${k} in input) { + newResult[${k}] = undefined; + } + } else { + payload.issues = payload.issues.concat( + ${id}.issues.map((iss) => ({ + ...iss, + path: iss.path ? [${k}, ...iss.path] : [${k}], + })) + ); } + } else if (${id}.value === undefined) { + if (${k} in input) newResult[${k}] = undefined; } else { newResult[${k}] = ${id}.value; } - - `); + `); + } + else { + const id = ids[key]; + // const id = ids[key]; + doc.write(`const ${id} = ${parseStr(key)};`); + doc.write(` + if (${id}.issues.length) payload.issues = payload.issues.concat(${id}.issues.map(iss => ({ + ...iss, + path: iss.path ? [${esc(key)}, ...iss.path] : [${esc(key)}] + })));`); + doc.write(`newResult[${esc(key)}] = ${id}.value`); + } } doc.write(`payload.value = newResult;`); doc.write(`return payload;`); @@ -53470,16 +53950,80 @@ const $ZodObjectJIT = /*@__PURE__*/ $constructor("$ZodObjectJIT", (inst, def) => }); return payload; } + const proms = []; if (jit && fastEnabled && ctx?.async === false && ctx.jitless !== true) { // always synchronous if (!fastpass) fastpass = generateFastpass(def.shape); payload = fastpass(payload, ctx); - if (!catchall) - return payload; - return handleCatchall([], input, payload, ctx, value, inst); } - return superParse(payload, ctx); + else { + payload.value = {}; + const shape = value.shape; + for (const key of value.keys) { + const el = shape[key]; + // do not add omitted optional keys + // if (!(key in input)) { + // if (optionalKeys.has(key)) continue; + // payload.issues.push({ + // code: "invalid_type", + // path: [key], + // expected: "nonoptional", + // note: `Missing required key: "${key}"`, + // input, + // inst, + // }); + // } + const r = el._zod.run({ value: input[key], issues: [] }, ctx); + const isOptional = el._zod.optin === "optional" && el._zod.optout === "optional"; + if (r instanceof Promise) { + proms.push(r.then((r) => isOptional ? handleOptionalObjectResult(r, payload, key, input) : handleObjectResult(r, payload, key))); + } + else if (isOptional) { + handleOptionalObjectResult(r, payload, key, input); + } + else { + handleObjectResult(r, payload, key); + } + } + } + if (!catchall) { + // return payload; + return proms.length ? Promise.all(proms).then(() => payload) : payload; + } + const unrecognized = []; + // iterate over input keys + const keySet = value.keySet; + const _catchall = catchall._zod; + const t = _catchall.def.type; + for (const key of Object.keys(input)) { + if (keySet.has(key)) + continue; + if (t === "never") { + unrecognized.push(key); + continue; + } + const r = _catchall.run({ value: input[key], issues: [] }, ctx); + if (r instanceof Promise) { + proms.push(r.then((r) => handleObjectResult(r, payload, key))); + } + else { + handleObjectResult(r, payload, key); + } + } + if (unrecognized.length) { + payload.issues.push({ + code: "unrecognized_keys", + keys: unrecognized, + input, + inst, + }); + } + if (!proms.length) + return payload; + return Promise.all(proms).then(() => { + return payload; + }); }; }); function handleUnionResults(results, final, inst, ctx) { @@ -53489,11 +54033,6 @@ function handleUnionResults(results, final, inst, ctx) { return final; } } - const nonaborted = results.filter((r) => !aborted(r)); - if (nonaborted.length === 1) { - final.value = nonaborted[0].value; - return nonaborted[0]; - } final.issues.push({ code: "invalid_union", input: final.value, @@ -53519,12 +54058,7 @@ const $ZodUnion = /*@__PURE__*/ $constructor("$ZodUnion", (inst, def) => { } return undefined; }); - const single = def.options.length === 1; - const first = def.options[0]._zod.run; inst._zod.parse = (payload, ctx) => { - if (single) { - return first(payload, ctx); - } let async = false; const results = []; for (const option of def.options) { @@ -53574,7 +54108,7 @@ $constructor("$ZodDiscriminatedUnion", (inst, def) => { const opts = def.options; const map = new Map(); for (const o of opts) { - const values = o._zod.propValues?.[def.discriminator]; + const values = o._zod.propValues[def.discriminator]; if (!values || values.size === 0) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`); for (const v of values) { @@ -53609,7 +54143,6 @@ $constructor("$ZodDiscriminatedUnion", (inst, def) => { code: "invalid_union", errors: [], note: "No matching discriminator", - discriminator: def.discriminator, input, path: [def.discriminator], inst, @@ -53697,6 +54230,7 @@ function handleIntersectionResults(result, left, right) { const $ZodTuple = /*@__PURE__*/ $constructor("$ZodTuple", (inst, def) => { $ZodType.init(inst, def); const items = def.items; + const optStart = items.length - [...items].reverse().findIndex((item) => item._zod.optin !== "optional"); inst._zod.parse = (payload, ctx) => { const input = payload.value; if (!Array.isArray(input)) { @@ -53710,17 +54244,15 @@ const $ZodTuple = /*@__PURE__*/ $constructor("$ZodTuple", (inst, def) => { } payload.value = []; const proms = []; - const reversedIndex = [...items].reverse().findIndex((item) => item._zod.optin !== "optional"); - const optStart = reversedIndex === -1 ? 0 : items.length - reversedIndex; if (!def.rest) { const tooBig = input.length > items.length; const tooSmall = input.length < optStart - 1; if (tooBig || tooSmall) { payload.issues.push({ - ...(tooBig ? { code: "too_big", maximum: items.length } : { code: "too_small", minimum: items.length }), input, inst, origin: "array", + ...(tooBig ? { code: "too_big", maximum: items.length } : { code: "too_small", minimum: items.length }), }); return payload; } @@ -53783,13 +54315,11 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => { return payload; } const proms = []; - const values = def.keyType._zod.values; - if (values) { + if (def.keyType._zod.values) { + const values = def.keyType._zod.values; payload.value = {}; - const recordKeys = new Set(); for (const key of values) { if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") { - recordKeys.add(typeof key === "number" ? key.toString() : key); const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx); if (result instanceof Promise) { proms.push(result.then((result) => { @@ -53809,7 +54339,7 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => { } let unrecognized; for (const key in input) { - if (!recordKeys.has(key)) { + if (!values.has(key)) { unrecognized = unrecognized ?? []; unrecognized.push(key); } @@ -53834,8 +54364,8 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => { } if (keyResult.issues.length) { payload.issues.push({ - code: "invalid_key", origin: "record", + code: "invalid_key", issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), input: key, path: [key], @@ -53867,7 +54397,7 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => { return payload; }; }); -const $ZodMap = /*@__PURE__*/ $constructor("$ZodMap", (inst, def) => { +const $ZodMap = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodMap", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload, ctx) => { const input = payload.value; @@ -53898,25 +54428,25 @@ const $ZodMap = /*@__PURE__*/ $constructor("$ZodMap", (inst, def) => { return Promise.all(proms).then(() => payload); return payload; }; -}); +}))); function handleMapResult(keyResult, valueResult, final, key, input, inst, ctx) { if (keyResult.issues.length) { - if (propertyKeyTypes.has(typeof key)) { - final.issues.push(...prefixIssues(key, keyResult.issues)); + if (util.propertyKeyTypes.has(typeof key)) { + final.issues.push(...util.prefixIssues(key, keyResult.issues)); } else { final.issues.push({ - code: "invalid_key", origin: "map", + code: "invalid_key", input, inst, - issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + issues: keyResult.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())), }); } } if (valueResult.issues.length) { - if (propertyKeyTypes.has(typeof key)) { - final.issues.push(...prefixIssues(key, valueResult.issues)); + if (util.propertyKeyTypes.has(typeof key)) { + final.issues.push(...util.prefixIssues(key, valueResult.issues)); } else { final.issues.push({ @@ -53925,13 +54455,13 @@ function handleMapResult(keyResult, valueResult, final, key, input, inst, ctx) { input, inst, key: key, - issues: valueResult.issues.map((iss) => finalizeIssue(iss, ctx, config())), + issues: valueResult.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())), }); } } final.value.set(keyResult.value, valueResult.value); } -const $ZodSet = /*@__PURE__*/ $constructor("$ZodSet", (inst, def) => { +const $ZodSet = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodSet", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload, ctx) => { const input = payload.value; @@ -53958,7 +54488,7 @@ const $ZodSet = /*@__PURE__*/ $constructor("$ZodSet", (inst, def) => { return Promise.all(proms).then(() => payload); return payload; }; -}); +}))); function handleSetResult(result, final) { if (result.issues.length) { final.issues.push(...result.issues); @@ -53968,15 +54498,14 @@ function handleSetResult(result, final) { const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => { $ZodType.init(inst, def); const values = getEnumValues(def.entries); - const valuesSet = new Set(values); - inst._zod.values = valuesSet; + inst._zod.values = new Set(values); inst._zod.pattern = new RegExp(`^(${values .filter((k) => propertyKeyTypes.has(typeof k)) .map((o) => (typeof o === "string" ? escapeRegex(o) : o.toString())) .join("|")})$`); inst._zod.parse = (payload, _ctx) => { const input = payload.value; - if (valuesSet.has(input)) { + if (inst._zod.values.has(input)) { return payload; } payload.issues.push({ @@ -53990,17 +54519,13 @@ const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => { }); const $ZodLiteral = /*@__PURE__*/ $constructor("$ZodLiteral", (inst, def) => { $ZodType.init(inst, def); - if (def.values.length === 0) { - throw new Error("Cannot create literal schema with no valid values"); - } - const values = new Set(def.values); - inst._zod.values = values; + inst._zod.values = new Set(def.values); inst._zod.pattern = new RegExp(`^(${def.values - .map((o) => (typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o))) + .map((o) => (typeof o === "string" ? escapeRegex(o) : o ? o.toString() : String(o))) .join("|")})$`); inst._zod.parse = (payload, _ctx) => { const input = payload.value; - if (values.has(input)) { + if (inst._zod.values.has(input)) { return payload; } payload.issues.push({ @@ -54012,11 +54537,10 @@ const $ZodLiteral = /*@__PURE__*/ $constructor("$ZodLiteral", (inst, def) => { return payload; }; }); -const $ZodFile = /*@__PURE__*/ $constructor("$ZodFile", (inst, def) => { +const $ZodFile = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodFile", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload, _ctx) => { const input = payload.value; - // @ts-ignore if (input instanceof File) return payload; payload.issues.push({ @@ -54027,15 +54551,12 @@ const $ZodFile = /*@__PURE__*/ $constructor("$ZodFile", (inst, def) => { }); return payload; }; -}); +}))); const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => { $ZodType.init(inst, def); - inst._zod.parse = (payload, ctx) => { - if (ctx.direction === "backward") { - throw new $ZodEncodeError(inst.constructor.name); - } + inst._zod.parse = (payload, _ctx) => { const _out = def.transform(payload.value, payload); - if (ctx.async) { + if (_ctx.async) { const output = _out instanceof Promise ? _out : Promise.resolve(_out); return output.then((output) => { payload.value = output; @@ -54049,12 +54570,6 @@ const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => return payload; }; }); -function handleOptionalResult(result, input) { - if (result.issues.length && input === undefined) { - return { issues: [], value: undefined }; - } - return result; -} const $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => { $ZodType.init(inst, def); inst._zod.optin = "optional"; @@ -54068,10 +54583,7 @@ const $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => { }); inst._zod.parse = (payload, ctx) => { if (def.innerType._zod.optin === "optional") { - const result = def.innerType._zod.run(payload, ctx); - if (result instanceof Promise) - return result.then((r) => handleOptionalResult(r, payload.value)); - return handleOptionalResult(result, payload.value); + return def.innerType._zod.run(payload, ctx); } if (payload.value === undefined) { return payload; @@ -54091,7 +54603,6 @@ const $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => { return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : undefined; }); inst._zod.parse = (payload, ctx) => { - // Forward direction (decode): allow null to pass through if (payload.value === null) return payload; return def.innerType._zod.run(payload, ctx); @@ -54103,18 +54614,13 @@ const $ZodDefault = /*@__PURE__*/ $constructor("$ZodDefault", (inst, def) => { inst._zod.optin = "optional"; defineLazy(inst._zod, "values", () => def.innerType._zod.values); inst._zod.parse = (payload, ctx) => { - if (ctx.direction === "backward") { - return def.innerType._zod.run(payload, ctx); - } - // Forward direction (decode): apply defaults for undefined input if (payload.value === undefined) { payload.value = def.defaultValue; /** - * $ZodDefault returns the default value immediately in forward direction. + * $ZodDefault always returns the default value immediately. * It doesn't pass the default value into the validator ("prefault"). There's no reason to pass the default value through validation. The validity of the default is enforced by TypeScript statically. Otherwise, it's the responsibility of the user to ensure the default is valid. In the case of pipes with divergent in/out types, you can specify the default on the `in` schema of your ZodPipe to set a "prefault" for the pipe. */ return payload; } - // Forward direction: continue with default handling const result = def.innerType._zod.run(payload, ctx); if (result instanceof Promise) { return result.then((result) => handleDefaultResult(result, def)); @@ -54133,10 +54639,6 @@ const $ZodPrefault = /*@__PURE__*/ $constructor("$ZodPrefault", (inst, def) => { inst._zod.optin = "optional"; defineLazy(inst._zod, "values", () => def.innerType._zod.values); inst._zod.parse = (payload, ctx) => { - if (ctx.direction === "backward") { - return def.innerType._zod.run(payload, ctx); - } - // Forward direction (decode): apply prefault for undefined input if (payload.value === undefined) { payload.value = def.defaultValue; } @@ -54168,12 +54670,9 @@ function handleNonOptionalResult(payload, inst) { } return payload; } -const $ZodSuccess = /*@__PURE__*/ $constructor("$ZodSuccess", (inst, def) => { +const $ZodSuccess = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodSuccess", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload, ctx) => { - if (ctx.direction === "backward") { - throw new $ZodEncodeError("ZodSuccess"); - } const result = def.innerType._zod.run(payload, ctx); if (result instanceof Promise) { return result.then((result) => { @@ -54184,17 +54683,13 @@ const $ZodSuccess = /*@__PURE__*/ $constructor("$ZodSuccess", (inst, def) => { payload.value = result.issues.length === 0; return payload; }; -}); +}))); const $ZodCatch = /*@__PURE__*/ $constructor("$ZodCatch", (inst, def) => { $ZodType.init(inst, def); - defineLazy(inst._zod, "optin", () => def.innerType._zod.optin); + inst._zod.optin = "optional"; defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); defineLazy(inst._zod, "values", () => def.innerType._zod.values); inst._zod.parse = (payload, ctx) => { - if (ctx.direction === "backward") { - return def.innerType._zod.run(payload, ctx); - } - // Forward direction (decode): apply catch logic const result = def.innerType._zod.run(payload, ctx); if (result instanceof Promise) { return result.then((result) => { @@ -54226,7 +54721,7 @@ const $ZodCatch = /*@__PURE__*/ $constructor("$ZodCatch", (inst, def) => { return payload; }; }); -const $ZodNaN = /*@__PURE__*/ $constructor("$ZodNaN", (inst, def) => { +const $ZodNaN = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodNaN", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload, _ctx) => { if (typeof payload.value !== "number" || !Number.isNaN(payload.value)) { @@ -54240,100 +54735,33 @@ const $ZodNaN = /*@__PURE__*/ $constructor("$ZodNaN", (inst, def) => { } return payload; }; -}); +}))); const $ZodPipe = /*@__PURE__*/ $constructor("$ZodPipe", (inst, def) => { $ZodType.init(inst, def); defineLazy(inst._zod, "values", () => def.in._zod.values); defineLazy(inst._zod, "optin", () => def.in._zod.optin); defineLazy(inst._zod, "optout", () => def.out._zod.optout); - defineLazy(inst._zod, "propValues", () => def.in._zod.propValues); inst._zod.parse = (payload, ctx) => { - if (ctx.direction === "backward") { - const right = def.out._zod.run(payload, ctx); - if (right instanceof Promise) { - return right.then((right) => handlePipeResult(right, def.in, ctx)); - } - return handlePipeResult(right, def.in, ctx); - } const left = def.in._zod.run(payload, ctx); if (left instanceof Promise) { - return left.then((left) => handlePipeResult(left, def.out, ctx)); + return left.then((left) => handlePipeResult(left, def, ctx)); } - return handlePipeResult(left, def.out, ctx); + return handlePipeResult(left, def, ctx); }; }); -function handlePipeResult(left, next, ctx) { - if (left.issues.length) { - // prevent further checks - left.aborted = true; +function handlePipeResult(left, def, ctx) { + if (aborted(left)) { return left; } - return next._zod.run({ value: left.value, issues: left.issues }, ctx); -} -const $ZodCodec = /*@__PURE__*/ $constructor("$ZodCodec", (inst, def) => { - $ZodType.init(inst, def); - defineLazy(inst._zod, "values", () => def.in._zod.values); - defineLazy(inst._zod, "optin", () => def.in._zod.optin); - defineLazy(inst._zod, "optout", () => def.out._zod.optout); - defineLazy(inst._zod, "propValues", () => def.in._zod.propValues); - inst._zod.parse = (payload, ctx) => { - const direction = ctx.direction || "forward"; - if (direction === "forward") { - const left = def.in._zod.run(payload, ctx); - if (left instanceof Promise) { - return left.then((left) => handleCodecAResult(left, def, ctx)); - } - return handleCodecAResult(left, def, ctx); - } - else { - const right = def.out._zod.run(payload, ctx); - if (right instanceof Promise) { - return right.then((right) => handleCodecAResult(right, def, ctx)); - } - return handleCodecAResult(right, def, ctx); - } - }; -}); -function handleCodecAResult(result, def, ctx) { - if (result.issues.length) { - // prevent further checks - result.aborted = true; - return result; - } - const direction = ctx.direction || "forward"; - if (direction === "forward") { - const transformed = def.transform(result.value, result); - if (transformed instanceof Promise) { - return transformed.then((value) => handleCodecTxResult(result, value, def.out, ctx)); - } - return handleCodecTxResult(result, transformed, def.out, ctx); - } - else { - const transformed = def.reverseTransform(result.value, result); - if (transformed instanceof Promise) { - return transformed.then((value) => handleCodecTxResult(result, value, def.in, ctx)); - } - return handleCodecTxResult(result, transformed, def.in, ctx); - } -} -function handleCodecTxResult(left, value, nextSchema, ctx) { - // Check if transform added any issues - if (left.issues.length) { - left.aborted = true; - return left; - } - return nextSchema._zod.run({ value, issues: left.issues }, ctx); + return def.out._zod.run({ value: left.value, issues: left.issues }, ctx); } const $ZodReadonly = /*@__PURE__*/ $constructor("$ZodReadonly", (inst, def) => { $ZodType.init(inst, def); defineLazy(inst._zod, "propValues", () => def.innerType._zod.propValues); defineLazy(inst._zod, "values", () => def.innerType._zod.values); - defineLazy(inst._zod, "optin", () => def.innerType?._zod?.optin); - defineLazy(inst._zod, "optout", () => def.innerType?._zod?.optout); + defineLazy(inst._zod, "optin", () => def.innerType._zod.optin); + defineLazy(inst._zod, "optout", () => def.innerType._zod.optout); inst._zod.parse = (payload, ctx) => { - if (ctx.direction === "backward") { - return def.innerType._zod.run(payload, ctx); - } const result = def.innerType._zod.run(payload, ctx); if (result instanceof Promise) { return result.then(handleReadonlyResult); @@ -54345,12 +54773,11 @@ function handleReadonlyResult(payload) { payload.value = Object.freeze(payload.value); return payload; } -const $ZodTemplateLiteral = /*@__PURE__*/ $constructor("$ZodTemplateLiteral", (inst, def) => { +const $ZodTemplateLiteral = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodTemplateLiteral", (inst, def) => { $ZodType.init(inst, def); const regexParts = []; for (const part of def.parts) { - if (typeof part === "object" && part !== null) { - // is Zod schema + if (part instanceof $ZodType) { if (!part._zod.pattern) { // if (!source) throw new Error(`Invalid template literal part, no pattern found: ${[...part._zod.traits].shift()}`); @@ -54362,8 +54789,8 @@ const $ZodTemplateLiteral = /*@__PURE__*/ $constructor("$ZodTemplateLiteral", (i const end = source.endsWith("$") ? source.length - 1 : source.length; regexParts.push(source.slice(start, end)); } - else if (part === null || primitiveTypes.has(typeof part)) { - regexParts.push(escapeRegex(`${part}`)); + else if (part === null || util.primitiveTypes.has(typeof part)) { + regexParts.push(util.escapeRegex(`${part}`)); } else { throw new Error(`Invalid template literal part: ${part}`); @@ -54386,118 +54813,32 @@ const $ZodTemplateLiteral = /*@__PURE__*/ $constructor("$ZodTemplateLiteral", (i input: payload.value, inst, code: "invalid_format", - format: def.format ?? "template_literal", + format: "template_literal", pattern: inst._zod.pattern.source, }); return payload; } return payload; }; -}); -const $ZodFunction = /*@__PURE__*/ $constructor("$ZodFunction", (inst, def) => { - $ZodType.init(inst, def); - inst._def = def; - inst._zod.def = def; - inst.implement = (func) => { - if (typeof func !== "function") { - throw new Error("implement() must be called with a function"); - } - return function (...args) { - const parsedArgs = inst._def.input ? parse_parse(inst._def.input, args) : args; - const result = Reflect.apply(func, this, parsedArgs); - if (inst._def.output) { - return parse_parse(inst._def.output, result); - } - return result; - }; - }; - inst.implementAsync = (func) => { - if (typeof func !== "function") { - throw new Error("implementAsync() must be called with a function"); - } - return async function (...args) { - const parsedArgs = inst._def.input ? await parseAsync(inst._def.input, args) : args; - const result = await Reflect.apply(func, this, parsedArgs); - if (inst._def.output) { - return await parseAsync(inst._def.output, result); - } - return result; - }; - }; - inst._zod.parse = (payload, _ctx) => { - if (typeof payload.value !== "function") { - payload.issues.push({ - code: "invalid_type", - expected: "function", - input: payload.value, - inst, - }); - return payload; - } - // Check if output is a promise type to determine if we should use async implementation - const hasPromiseOutput = inst._def.output && inst._def.output._zod.def.type === "promise"; - if (hasPromiseOutput) { - payload.value = inst.implementAsync(payload.value); - } - else { - payload.value = inst.implement(payload.value); - } - return payload; - }; - inst.input = (...args) => { - const F = inst.constructor; - if (Array.isArray(args[0])) { - return new F({ - type: "function", - input: new $ZodTuple({ - type: "tuple", - items: args[0], - rest: args[1], - }), - output: inst._def.output, - }); - } - return new F({ - type: "function", - input: args[0], - output: inst._def.output, - }); - }; - inst.output = (output) => { - const F = inst.constructor; - return new F({ - type: "function", - input: inst._def.input, - output, - }); - }; - return inst; -}); -const $ZodPromise = /*@__PURE__*/ $constructor("$ZodPromise", (inst, def) => { +}))); +const $ZodPromise = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodPromise", (inst, def) => { $ZodType.init(inst, def); inst._zod.parse = (payload, ctx) => { return Promise.resolve(payload.value).then((inner) => def.innerType._zod.run({ value: inner, issues: [] }, ctx)); }; -}); -const $ZodLazy = /*@__PURE__*/ $constructor("$ZodLazy", (inst, def) => { +}))); +const $ZodLazy = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("$ZodLazy", (inst, def) => { $ZodType.init(inst, def); - // let _innerType!: any; - // util.defineLazy(def, "getter", () => { - // if (!_innerType) { - // _innerType = def.getter(); - // } - // return () => _innerType; - // }); - defineLazy(inst._zod, "innerType", () => def.getter()); - defineLazy(inst._zod, "pattern", () => inst._zod.innerType?._zod?.pattern); - defineLazy(inst._zod, "propValues", () => inst._zod.innerType?._zod?.propValues); - defineLazy(inst._zod, "optin", () => inst._zod.innerType?._zod?.optin ?? undefined); - defineLazy(inst._zod, "optout", () => inst._zod.innerType?._zod?.optout ?? undefined); + util.defineLazy(inst._zod, "innerType", () => def.getter()); + util.defineLazy(inst._zod, "pattern", () => inst._zod.innerType._zod.pattern); + util.defineLazy(inst._zod, "propValues", () => inst._zod.innerType._zod.propValues); + util.defineLazy(inst._zod, "optin", () => inst._zod.innerType._zod.optin); + util.defineLazy(inst._zod, "optout", () => inst._zod.innerType._zod.optout); inst._zod.parse = (payload, ctx) => { const inner = inst._zod.innerType; return inner._zod.run(payload, ctx); }; -}); +}))); const $ZodCustom = /*@__PURE__*/ $constructor("$ZodCustom", (inst, def) => { $ZodCheck.init(inst, def); $ZodType.init(inst, def); @@ -54530,6280 +54871,390 @@ function handleRefineResult(result, payload, input, inst) { } } -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ar.js +;// CONCATENATED MODULE: ./node_modules/zod/v4/core/api.js -const error = () => { - const Sizable = { - string: { unit: "حرف", verb: "أن يحوي" }, - file: { unit: "بايت", verb: "أن يحوي" }, - array: { unit: "عنصر", verb: "أن يحوي" }, - set: { unit: "عنصر", verb: "أن يحوي" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "مدخل", - email: "بريد إلكتروني", - url: "رابط", - emoji: "إيموجي", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "تاريخ ووقت بمعيار ISO", - date: "تاريخ بمعيار ISO", - time: "وقت بمعيار ISO", - duration: "مدة بمعيار ISO", - ipv4: "عنوان IPv4", - ipv6: "عنوان IPv6", - cidrv4: "مدى عناوين بصيغة IPv4", - cidrv6: "مدى عناوين بصيغة IPv6", - base64: "نَص بترميز base64-encoded", - base64url: "نَص بترميز base64url-encoded", - json_string: "نَص على هيئة JSON", - e164: "رقم هاتف بمعيار E.164", - jwt: "JWT", - template_literal: "مدخل", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `مدخلات غير مقبولة: يفترض إدخال ${issue.expected}، ولكن تم إدخال ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `مدخلات غير مقبولة: يفترض إدخال ${stringifyPrimitive(issue.values[0])}`; - return `اختيار غير مقبول: يتوقع انتقاء أحد هذه الخيارات: ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return ` أكبر من اللازم: يفترض أن تكون ${issue.origin ?? "القيمة"} ${adj} ${issue.maximum.toString()} ${sizing.unit ?? "عنصر"}`; - return `أكبر من اللازم: يفترض أن تكون ${issue.origin ?? "القيمة"} ${adj} ${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `أصغر من اللازم: يفترض لـ ${issue.origin} أن يكون ${adj} ${issue.minimum.toString()} ${sizing.unit}`; - } - return `أصغر من اللازم: يفترض لـ ${issue.origin} أن يكون ${adj} ${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `نَص غير مقبول: يجب أن يبدأ بـ "${issue.prefix}"`; - if (_issue.format === "ends_with") - return `نَص غير مقبول: يجب أن ينتهي بـ "${_issue.suffix}"`; - if (_issue.format === "includes") - return `نَص غير مقبول: يجب أن يتضمَّن "${_issue.includes}"`; - if (_issue.format === "regex") - return `نَص غير مقبول: يجب أن يطابق النمط ${_issue.pattern}`; - return `${Nouns[_issue.format] ?? issue.format} غير مقبول`; - } - case "not_multiple_of": - return `رقم غير مقبول: يجب أن يكون من مضاعفات ${issue.divisor}`; - case "unrecognized_keys": - return `معرف${issue.keys.length > 1 ? "ات" : ""} غريب${issue.keys.length > 1 ? "ة" : ""}: ${joinValues(issue.keys, "، ")}`; - case "invalid_key": - return `معرف غير مقبول في ${issue.origin}`; - case "invalid_union": - return "مدخل غير مقبول"; - case "invalid_element": - return `مدخل غير مقبول في ${issue.origin}`; - default: - return "مدخل غير مقبول"; - } - }; -}; -/* harmony default export */ function ar() { - return { - localeError: error(), - }; -} -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/az.js -const az_error = () => { - const Sizable = { - string: { unit: "simvol", verb: "olmalıdır" }, - file: { unit: "bayt", verb: "olmalıdır" }, - array: { unit: "element", verb: "olmalıdır" }, - set: { unit: "element", verb: "olmalıdır" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "input", - email: "email address", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO datetime", - date: "ISO date", - time: "ISO time", - duration: "ISO duration", - ipv4: "IPv4 address", - ipv6: "IPv6 address", - cidrv4: "IPv4 range", - cidrv6: "IPv6 range", - base64: "base64-encoded string", - base64url: "base64url-encoded string", - json_string: "JSON string", - e164: "E.164 number", - jwt: "JWT", - template_literal: "input", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Yanlış dəyər: gözlənilən ${issue.expected}, daxil olan ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Yanlış dəyər: gözlənilən ${stringifyPrimitive(issue.values[0])}`; - return `Yanlış seçim: aşağıdakılardan biri olmalıdır: ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Çox böyük: gözlənilən ${issue.origin ?? "dəyər"} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "element"}`; - return `Çox böyük: gözlənilən ${issue.origin ?? "dəyər"} ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Çox kiçik: gözlənilən ${issue.origin} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - return `Çox kiçik: gözlənilən ${issue.origin} ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Yanlış mətn: "${_issue.prefix}" ilə başlamalıdır`; - if (_issue.format === "ends_with") - return `Yanlış mətn: "${_issue.suffix}" ilə bitməlidir`; - if (_issue.format === "includes") - return `Yanlış mətn: "${_issue.includes}" daxil olmalıdır`; - if (_issue.format === "regex") - return `Yanlış mətn: ${_issue.pattern} şablonuna uyğun olmalıdır`; - return `Yanlış ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Yanlış ədəd: ${issue.divisor} ilə bölünə bilən olmalıdır`; - case "unrecognized_keys": - return `Tanınmayan açar${issue.keys.length > 1 ? "lar" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `${issue.origin} daxilində yanlış açar`; - case "invalid_union": - return "Yanlış dəyər"; - case "invalid_element": - return `${issue.origin} daxilində yanlış dəyər`; - default: - return `Yanlış dəyər`; - } - }; -}; -/* harmony default export */ function az() { - return { - localeError: az_error(), - }; +function _string(Class, params) { + return new Class({ + type: "string", + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/be.js - -function getBelarusianPlural(count, one, few, many) { - const absCount = Math.abs(count); - const lastDigit = absCount % 10; - const lastTwoDigits = absCount % 100; - if (lastTwoDigits >= 11 && lastTwoDigits <= 19) { - return many; - } - if (lastDigit === 1) { - return one; - } - if (lastDigit >= 2 && lastDigit <= 4) { - return few; - } - return many; +function _coercedString(Class, params) { + return new Class({ + type: "string", + coerce: true, + ...util.normalizeParams(params), + }); } -const be_error = () => { - const Sizable = { - string: { - unit: { - one: "сімвал", - few: "сімвалы", - many: "сімвалаў", - }, - verb: "мець", - }, - array: { - unit: { - one: "элемент", - few: "элементы", - many: "элементаў", - }, - verb: "мець", - }, - set: { - unit: { - one: "элемент", - few: "элементы", - many: "элементаў", - }, - verb: "мець", - }, - file: { - unit: { - one: "байт", - few: "байты", - many: "байтаў", - }, - verb: "мець", - }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "лік"; - } - case "object": { - if (Array.isArray(data)) { - return "масіў"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "увод", - email: "email адрас", - url: "URL", - emoji: "эмодзі", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO дата і час", - date: "ISO дата", - time: "ISO час", - duration: "ISO працягласць", - ipv4: "IPv4 адрас", - ipv6: "IPv6 адрас", - cidrv4: "IPv4 дыяпазон", - cidrv6: "IPv6 дыяпазон", - base64: "радок у фармаце base64", - base64url: "радок у фармаце base64url", - json_string: "JSON радок", - e164: "нумар E.164", - jwt: "JWT", - template_literal: "увод", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Няправільны ўвод: чакаўся ${issue.expected}, атрымана ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Няправільны ўвод: чакалася ${stringifyPrimitive(issue.values[0])}`; - return `Няправільны варыянт: чакаўся адзін з ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) { - const maxValue = Number(issue.maximum); - const unit = getBelarusianPlural(maxValue, sizing.unit.one, sizing.unit.few, sizing.unit.many); - return `Занадта вялікі: чакалася, што ${issue.origin ?? "значэнне"} павінна ${sizing.verb} ${adj}${issue.maximum.toString()} ${unit}`; - } - return `Занадта вялікі: чакалася, што ${issue.origin ?? "значэнне"} павінна быць ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - const minValue = Number(issue.minimum); - const unit = getBelarusianPlural(minValue, sizing.unit.one, sizing.unit.few, sizing.unit.many); - return `Занадта малы: чакалася, што ${issue.origin} павінна ${sizing.verb} ${adj}${issue.minimum.toString()} ${unit}`; - } - return `Занадта малы: чакалася, што ${issue.origin} павінна быць ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Няправільны радок: павінен пачынацца з "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Няправільны радок: павінен заканчвацца на "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Няправільны радок: павінен змяшчаць "${_issue.includes}"`; - if (_issue.format === "regex") - return `Няправільны радок: павінен адпавядаць шаблону ${_issue.pattern}`; - return `Няправільны ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Няправільны лік: павінен быць кратным ${issue.divisor}`; - case "unrecognized_keys": - return `Нераспазнаны ${issue.keys.length > 1 ? "ключы" : "ключ"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Няправільны ключ у ${issue.origin}`; - case "invalid_union": - return "Няправільны ўвод"; - case "invalid_element": - return `Няправільнае значэнне ў ${issue.origin}`; - default: - return `Няправільны ўвод`; - } - }; -}; -/* harmony default export */ function be() { - return { - localeError: be_error(), - }; +function _email(Class, params) { + return new Class({ + type: "string", + format: "email", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/bg.js - -const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "число"; - } - case "object": { - if (Array.isArray(data)) { - return "масив"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; -}; -const bg_error = () => { - const Sizable = { - string: { unit: "символа", verb: "да съдържа" }, - file: { unit: "байта", verb: "да съдържа" }, - array: { unit: "елемента", verb: "да съдържа" }, - set: { unit: "елемента", verb: "да съдържа" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const Nouns = { - regex: "вход", - email: "имейл адрес", - url: "URL", - emoji: "емоджи", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO време", - date: "ISO дата", - time: "ISO време", - duration: "ISO продължителност", - ipv4: "IPv4 адрес", - ipv6: "IPv6 адрес", - cidrv4: "IPv4 диапазон", - cidrv6: "IPv6 диапазон", - base64: "base64-кодиран низ", - base64url: "base64url-кодиран низ", - json_string: "JSON низ", - e164: "E.164 номер", - jwt: "JWT", - template_literal: "вход", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Невалиден вход: очакван ${issue.expected}, получен ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Невалиден вход: очакван ${stringifyPrimitive(issue.values[0])}`; - return `Невалидна опция: очаквано едно от ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Твърде голямо: очаква се ${issue.origin ?? "стойност"} да съдържа ${adj}${issue.maximum.toString()} ${sizing.unit ?? "елемента"}`; - return `Твърде голямо: очаква се ${issue.origin ?? "стойност"} да бъде ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Твърде малко: очаква се ${issue.origin} да съдържа ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Твърде малко: очаква се ${issue.origin} да бъде ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Невалиден низ: трябва да започва с "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `Невалиден низ: трябва да завършва с "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Невалиден низ: трябва да включва "${_issue.includes}"`; - if (_issue.format === "regex") - return `Невалиден низ: трябва да съвпада с ${_issue.pattern}`; - let invalid_adj = "Невалиден"; - if (_issue.format === "emoji") - invalid_adj = "Невалидно"; - if (_issue.format === "datetime") - invalid_adj = "Невалидно"; - if (_issue.format === "date") - invalid_adj = "Невалидна"; - if (_issue.format === "time") - invalid_adj = "Невалидно"; - if (_issue.format === "duration") - invalid_adj = "Невалидна"; - return `${invalid_adj} ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Невалидно число: трябва да бъде кратно на ${issue.divisor}`; - case "unrecognized_keys": - return `Неразпознат${issue.keys.length > 1 ? "и" : ""} ключ${issue.keys.length > 1 ? "ове" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Невалиден ключ в ${issue.origin}`; - case "invalid_union": - return "Невалиден вход"; - case "invalid_element": - return `Невалидна стойност в ${issue.origin}`; - default: - return `Невалиден вход`; - } - }; -}; -/* harmony default export */ function bg() { - return { - localeError: bg_error(), - }; +function _guid(Class, params) { + return new Class({ + type: "string", + format: "guid", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ca.js - -const ca_error = () => { - const Sizable = { - string: { unit: "caràcters", verb: "contenir" }, - file: { unit: "bytes", verb: "contenir" }, - array: { unit: "elements", verb: "contenir" }, - set: { unit: "elements", verb: "contenir" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "entrada", - email: "adreça electrònica", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "data i hora ISO", - date: "data ISO", - time: "hora ISO", - duration: "durada ISO", - ipv4: "adreça IPv4", - ipv6: "adreça IPv6", - cidrv4: "rang IPv4", - cidrv6: "rang IPv6", - base64: "cadena codificada en base64", - base64url: "cadena codificada en base64url", - json_string: "cadena JSON", - e164: "número E.164", - jwt: "JWT", - template_literal: "entrada", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Tipus invàlid: s'esperava ${issue.expected}, s'ha rebut ${parsedType(issue.input)}`; - // return `Tipus invàlid: s'esperava ${issue.expected}, s'ha rebut ${util.getParsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Valor invàlid: s'esperava ${stringifyPrimitive(issue.values[0])}`; - return `Opció invàlida: s'esperava una de ${joinValues(issue.values, " o ")}`; - case "too_big": { - const adj = issue.inclusive ? "com a màxim" : "menys de"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Massa gran: s'esperava que ${issue.origin ?? "el valor"} contingués ${adj} ${issue.maximum.toString()} ${sizing.unit ?? "elements"}`; - return `Massa gran: s'esperava que ${issue.origin ?? "el valor"} fos ${adj} ${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? "com a mínim" : "més de"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Massa petit: s'esperava que ${issue.origin} contingués ${adj} ${issue.minimum.toString()} ${sizing.unit}`; - } - return `Massa petit: s'esperava que ${issue.origin} fos ${adj} ${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Format invàlid: ha de començar amb "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `Format invàlid: ha d'acabar amb "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Format invàlid: ha d'incloure "${_issue.includes}"`; - if (_issue.format === "regex") - return `Format invàlid: ha de coincidir amb el patró ${_issue.pattern}`; - return `Format invàlid per a ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Número invàlid: ha de ser múltiple de ${issue.divisor}`; - case "unrecognized_keys": - return `Clau${issue.keys.length > 1 ? "s" : ""} no reconeguda${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Clau invàlida a ${issue.origin}`; - case "invalid_union": - return "Entrada invàlida"; // Could also be "Tipus d'unió invàlid" but "Entrada invàlida" is more general - case "invalid_element": - return `Element invàlid a ${issue.origin}`; - default: - return `Entrada invàlida`; - } - }; -}; -/* harmony default export */ function ca() { - return { - localeError: ca_error(), - }; +function _uuid(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/cs.js - -const cs_error = () => { - const Sizable = { - string: { unit: "znaků", verb: "mít" }, - file: { unit: "bajtů", verb: "mít" }, - array: { unit: "prvků", verb: "mít" }, - set: { unit: "prvků", verb: "mít" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "číslo"; - } - case "string": { - return "řetězec"; - } - case "boolean": { - return "boolean"; - } - case "bigint": { - return "bigint"; - } - case "function": { - return "funkce"; - } - case "symbol": { - return "symbol"; - } - case "undefined": { - return "undefined"; - } - case "object": { - if (Array.isArray(data)) { - return "pole"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "regulární výraz", - email: "e-mailová adresa", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "datum a čas ve formátu ISO", - date: "datum ve formátu ISO", - time: "čas ve formátu ISO", - duration: "doba trvání ISO", - ipv4: "IPv4 adresa", - ipv6: "IPv6 adresa", - cidrv4: "rozsah IPv4", - cidrv6: "rozsah IPv6", - base64: "řetězec zakódovaný ve formátu base64", - base64url: "řetězec zakódovaný ve formátu base64url", - json_string: "řetězec ve formátu JSON", - e164: "číslo E.164", - jwt: "JWT", - template_literal: "vstup", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Neplatný vstup: očekáváno ${issue.expected}, obdrženo ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Neplatný vstup: očekáváno ${stringifyPrimitive(issue.values[0])}`; - return `Neplatná možnost: očekávána jedna z hodnot ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Hodnota je příliš velká: ${issue.origin ?? "hodnota"} musí mít ${adj}${issue.maximum.toString()} ${sizing.unit ?? "prvků"}`; - } - return `Hodnota je příliš velká: ${issue.origin ?? "hodnota"} musí být ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Hodnota je příliš malá: ${issue.origin ?? "hodnota"} musí mít ${adj}${issue.minimum.toString()} ${sizing.unit ?? "prvků"}`; - } - return `Hodnota je příliš malá: ${issue.origin ?? "hodnota"} musí být ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Neplatný řetězec: musí začínat na "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Neplatný řetězec: musí končit na "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Neplatný řetězec: musí obsahovat "${_issue.includes}"`; - if (_issue.format === "regex") - return `Neplatný řetězec: musí odpovídat vzoru ${_issue.pattern}`; - return `Neplatný formát ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Neplatné číslo: musí být násobkem ${issue.divisor}`; - case "unrecognized_keys": - return `Neznámé klíče: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Neplatný klíč v ${issue.origin}`; - case "invalid_union": - return "Neplatný vstup"; - case "invalid_element": - return `Neplatná hodnota v ${issue.origin}`; - default: - return `Neplatný vstup`; - } - }; -}; -/* harmony default export */ function cs() { - return { - localeError: cs_error(), - }; +function _uuidv4(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v4", + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/da.js - -const da_error = () => { - const Sizable = { - string: { unit: "tegn", verb: "havde" }, - file: { unit: "bytes", verb: "havde" }, - array: { unit: "elementer", verb: "indeholdt" }, - set: { unit: "elementer", verb: "indeholdt" }, - }; - const TypeNames = { - string: "streng", - number: "tal", - boolean: "boolean", - array: "liste", - object: "objekt", - set: "sæt", - file: "fil", - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - function getTypeName(type) { - return TypeNames[type] ?? type; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "tal"; - } - case "object": { - if (Array.isArray(data)) { - return "liste"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - return "objekt"; - } - } - return t; - }; - const Nouns = { - regex: "input", - email: "e-mailadresse", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO dato- og klokkeslæt", - date: "ISO-dato", - time: "ISO-klokkeslæt", - duration: "ISO-varighed", - ipv4: "IPv4-område", - ipv6: "IPv6-område", - cidrv4: "IPv4-spektrum", - cidrv6: "IPv6-spektrum", - base64: "base64-kodet streng", - base64url: "base64url-kodet streng", - json_string: "JSON-streng", - e164: "E.164-nummer", - jwt: "JWT", - template_literal: "input", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Ugyldigt input: forventede ${getTypeName(issue.expected)}, fik ${getTypeName(parsedType(issue.input))}`; - case "invalid_value": - if (issue.values.length === 1) - return `Ugyldig værdi: forventede ${stringifyPrimitive(issue.values[0])}`; - return `Ugyldigt valg: forventede en af følgende ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - const origin = getTypeName(issue.origin); - if (sizing) - return `For stor: forventede ${origin ?? "value"} ${sizing.verb} ${adj} ${issue.maximum.toString()} ${sizing.unit ?? "elementer"}`; - return `For stor: forventede ${origin ?? "value"} havde ${adj} ${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - const origin = getTypeName(issue.origin); - if (sizing) { - return `For lille: forventede ${origin} ${sizing.verb} ${adj} ${issue.minimum.toString()} ${sizing.unit}`; - } - return `For lille: forventede ${origin} havde ${adj} ${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Ugyldig streng: skal starte med "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Ugyldig streng: skal ende med "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Ugyldig streng: skal indeholde "${_issue.includes}"`; - if (_issue.format === "regex") - return `Ugyldig streng: skal matche mønsteret ${_issue.pattern}`; - return `Ugyldig ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Ugyldigt tal: skal være deleligt med ${issue.divisor}`; - case "unrecognized_keys": - return `${issue.keys.length > 1 ? "Ukendte nøgler" : "Ukendt nøgle"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Ugyldig nøgle i ${issue.origin}`; - case "invalid_union": - return "Ugyldigt input: matcher ingen af de tilladte typer"; - case "invalid_element": - return `Ugyldig værdi i ${issue.origin}`; - default: - return `Ugyldigt input`; - } - }; -}; -/* harmony default export */ function da() { - return { - localeError: da_error(), - }; +function _uuidv6(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v6", + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/de.js - -const de_error = () => { - const Sizable = { - string: { unit: "Zeichen", verb: "zu haben" }, - file: { unit: "Bytes", verb: "zu haben" }, - array: { unit: "Elemente", verb: "zu haben" }, - set: { unit: "Elemente", verb: "zu haben" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "Zahl"; - } - case "object": { - if (Array.isArray(data)) { - return "Array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "Eingabe", - email: "E-Mail-Adresse", - url: "URL", - emoji: "Emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO-Datum und -Uhrzeit", - date: "ISO-Datum", - time: "ISO-Uhrzeit", - duration: "ISO-Dauer", - ipv4: "IPv4-Adresse", - ipv6: "IPv6-Adresse", - cidrv4: "IPv4-Bereich", - cidrv6: "IPv6-Bereich", - base64: "Base64-codierter String", - base64url: "Base64-URL-codierter String", - json_string: "JSON-String", - e164: "E.164-Nummer", - jwt: "JWT", - template_literal: "Eingabe", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Ungültige Eingabe: erwartet ${issue.expected}, erhalten ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Ungültige Eingabe: erwartet ${stringifyPrimitive(issue.values[0])}`; - return `Ungültige Option: erwartet eine von ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Zu groß: erwartet, dass ${issue.origin ?? "Wert"} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "Elemente"} hat`; - return `Zu groß: erwartet, dass ${issue.origin ?? "Wert"} ${adj}${issue.maximum.toString()} ist`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Zu klein: erwartet, dass ${issue.origin} ${adj}${issue.minimum.toString()} ${sizing.unit} hat`; - } - return `Zu klein: erwartet, dass ${issue.origin} ${adj}${issue.minimum.toString()} ist`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Ungültiger String: muss mit "${_issue.prefix}" beginnen`; - if (_issue.format === "ends_with") - return `Ungültiger String: muss mit "${_issue.suffix}" enden`; - if (_issue.format === "includes") - return `Ungültiger String: muss "${_issue.includes}" enthalten`; - if (_issue.format === "regex") - return `Ungültiger String: muss dem Muster ${_issue.pattern} entsprechen`; - return `Ungültig: ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Ungültige Zahl: muss ein Vielfaches von ${issue.divisor} sein`; - case "unrecognized_keys": - return `${issue.keys.length > 1 ? "Unbekannte Schlüssel" : "Unbekannter Schlüssel"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Ungültiger Schlüssel in ${issue.origin}`; - case "invalid_union": - return "Ungültige Eingabe"; - case "invalid_element": - return `Ungültiger Wert in ${issue.origin}`; - default: - return `Ungültige Eingabe`; - } - }; -}; -/* harmony default export */ function de() { - return { - localeError: de_error(), - }; +function _uuidv7(Class, params) { + return new Class({ + type: "string", + format: "uuid", + check: "string_format", + abort: false, + version: "v7", + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/en.js - -const en_parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; -}; -const en_error = () => { - const Sizable = { - string: { unit: "characters", verb: "to have" }, - file: { unit: "bytes", verb: "to have" }, - array: { unit: "items", verb: "to have" }, - set: { unit: "items", verb: "to have" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const Nouns = { - regex: "input", - email: "email address", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO datetime", - date: "ISO date", - time: "ISO time", - duration: "ISO duration", - ipv4: "IPv4 address", - ipv6: "IPv6 address", - mac: "MAC address", - cidrv4: "IPv4 range", - cidrv6: "IPv6 range", - base64: "base64-encoded string", - base64url: "base64url-encoded string", - json_string: "JSON string", - e164: "E.164 number", - jwt: "JWT", - template_literal: "input", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Invalid input: expected ${issue.expected}, received ${en_parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Invalid input: expected ${stringifyPrimitive(issue.values[0])}`; - return `Invalid option: expected one of ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Too big: expected ${issue.origin ?? "value"} to have ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elements"}`; - return `Too big: expected ${issue.origin ?? "value"} to be ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Too small: expected ${issue.origin} to have ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Too small: expected ${issue.origin} to be ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Invalid string: must start with "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `Invalid string: must end with "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Invalid string: must include "${_issue.includes}"`; - if (_issue.format === "regex") - return `Invalid string: must match pattern ${_issue.pattern}`; - return `Invalid ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Invalid number: must be a multiple of ${issue.divisor}`; - case "unrecognized_keys": - return `Unrecognized key${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Invalid key in ${issue.origin}`; - case "invalid_union": - return "Invalid input"; - case "invalid_element": - return `Invalid value in ${issue.origin}`; - default: - return `Invalid input`; - } - }; -}; -/* harmony default export */ function en() { - return { - localeError: en_error(), - }; +function _url(Class, params) { + return new Class({ + type: "string", + format: "url", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/eo.js - -const eo_parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "nombro"; - } - case "object": { - if (Array.isArray(data)) { - return "tabelo"; - } - if (data === null) { - return "senvalora"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; -}; -const eo_error = () => { - const Sizable = { - string: { unit: "karaktrojn", verb: "havi" }, - file: { unit: "bajtojn", verb: "havi" }, - array: { unit: "elementojn", verb: "havi" }, - set: { unit: "elementojn", verb: "havi" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const Nouns = { - regex: "enigo", - email: "retadreso", - url: "URL", - emoji: "emoĝio", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO-datotempo", - date: "ISO-dato", - time: "ISO-tempo", - duration: "ISO-daŭro", - ipv4: "IPv4-adreso", - ipv6: "IPv6-adreso", - cidrv4: "IPv4-rango", - cidrv6: "IPv6-rango", - base64: "64-ume kodita karaktraro", - base64url: "URL-64-ume kodita karaktraro", - json_string: "JSON-karaktraro", - e164: "E.164-nombro", - jwt: "JWT", - template_literal: "enigo", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Nevalida enigo: atendiĝis ${issue.expected}, riceviĝis ${eo_parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Nevalida enigo: atendiĝis ${stringifyPrimitive(issue.values[0])}`; - return `Nevalida opcio: atendiĝis unu el ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Tro granda: atendiĝis ke ${issue.origin ?? "valoro"} havu ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementojn"}`; - return `Tro granda: atendiĝis ke ${issue.origin ?? "valoro"} havu ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Tro malgranda: atendiĝis ke ${issue.origin} havu ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Tro malgranda: atendiĝis ke ${issue.origin} estu ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Nevalida karaktraro: devas komenciĝi per "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Nevalida karaktraro: devas finiĝi per "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Nevalida karaktraro: devas inkluzivi "${_issue.includes}"`; - if (_issue.format === "regex") - return `Nevalida karaktraro: devas kongrui kun la modelo ${_issue.pattern}`; - return `Nevalida ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Nevalida nombro: devas esti oblo de ${issue.divisor}`; - case "unrecognized_keys": - return `Nekonata${issue.keys.length > 1 ? "j" : ""} ŝlosilo${issue.keys.length > 1 ? "j" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Nevalida ŝlosilo en ${issue.origin}`; - case "invalid_union": - return "Nevalida enigo"; - case "invalid_element": - return `Nevalida valoro en ${issue.origin}`; - default: - return `Nevalida enigo`; - } - }; -}; -/* harmony default export */ function eo() { - return { - localeError: eo_error(), - }; +function api_emoji(Class, params) { + return new Class({ + type: "string", + format: "emoji", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/es.js - -const es_error = () => { - const Sizable = { - string: { unit: "caracteres", verb: "tener" }, - file: { unit: "bytes", verb: "tener" }, - array: { unit: "elementos", verb: "tener" }, - set: { unit: "elementos", verb: "tener" }, - }; - const TypeNames = { - string: "texto", - number: "número", - boolean: "booleano", - array: "arreglo", - object: "objeto", - set: "conjunto", - file: "archivo", - date: "fecha", - bigint: "número grande", - symbol: "símbolo", - undefined: "indefinido", - null: "nulo", - function: "función", - map: "mapa", - record: "registro", - tuple: "tupla", - enum: "enumeración", - union: "unión", - literal: "literal", - promise: "promesa", - void: "vacío", - never: "nunca", - unknown: "desconocido", - any: "cualquiera", - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - function getTypeName(type) { - return TypeNames[type] ?? type; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype) { - return data.constructor.name; - } - return "object"; - } - } - return t; - }; - const Nouns = { - regex: "entrada", - email: "dirección de correo electrónico", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "fecha y hora ISO", - date: "fecha ISO", - time: "hora ISO", - duration: "duración ISO", - ipv4: "dirección IPv4", - ipv6: "dirección IPv6", - cidrv4: "rango IPv4", - cidrv6: "rango IPv6", - base64: "cadena codificada en base64", - base64url: "URL codificada en base64", - json_string: "cadena JSON", - e164: "número E.164", - jwt: "JWT", - template_literal: "entrada", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Entrada inválida: se esperaba ${getTypeName(issue.expected)}, recibido ${getTypeName(parsedType(issue.input))}`; - // return `Entrada inválida: se esperaba ${issue.expected}, recibido ${util.getParsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Entrada inválida: se esperaba ${stringifyPrimitive(issue.values[0])}`; - return `Opción inválida: se esperaba una de ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - const origin = getTypeName(issue.origin); - if (sizing) - return `Demasiado grande: se esperaba que ${origin ?? "valor"} tuviera ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementos"}`; - return `Demasiado grande: se esperaba que ${origin ?? "valor"} fuera ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - const origin = getTypeName(issue.origin); - if (sizing) { - return `Demasiado pequeño: se esperaba que ${origin} tuviera ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Demasiado pequeño: se esperaba que ${origin} fuera ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Cadena inválida: debe comenzar con "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Cadena inválida: debe terminar en "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Cadena inválida: debe incluir "${_issue.includes}"`; - if (_issue.format === "regex") - return `Cadena inválida: debe coincidir con el patrón ${_issue.pattern}`; - return `Inválido ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Número inválido: debe ser múltiplo de ${issue.divisor}`; - case "unrecognized_keys": - return `Llave${issue.keys.length > 1 ? "s" : ""} desconocida${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Llave inválida en ${getTypeName(issue.origin)}`; - case "invalid_union": - return "Entrada inválida"; - case "invalid_element": - return `Valor inválido en ${getTypeName(issue.origin)}`; - default: - return `Entrada inválida`; - } - }; -}; -/* harmony default export */ function es() { - return { - localeError: es_error(), - }; +function _nanoid(Class, params) { + return new Class({ + type: "string", + format: "nanoid", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/fa.js - -const fa_error = () => { - const Sizable = { - string: { unit: "کاراکتر", verb: "داشته باشد" }, - file: { unit: "بایت", verb: "داشته باشد" }, - array: { unit: "آیتم", verb: "داشته باشد" }, - set: { unit: "آیتم", verb: "داشته باشد" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "عدد"; - } - case "object": { - if (Array.isArray(data)) { - return "آرایه"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "ورودی", - email: "آدرس ایمیل", - url: "URL", - emoji: "ایموجی", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "تاریخ و زمان ایزو", - date: "تاریخ ایزو", - time: "زمان ایزو", - duration: "مدت زمان ایزو", - ipv4: "IPv4 آدرس", - ipv6: "IPv6 آدرس", - cidrv4: "IPv4 دامنه", - cidrv6: "IPv6 دامنه", - base64: "base64-encoded رشته", - base64url: "base64url-encoded رشته", - json_string: "JSON رشته", - e164: "E.164 عدد", - jwt: "JWT", - template_literal: "ورودی", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `ورودی نامعتبر: می‌بایست ${issue.expected} می‌بود، ${parsedType(issue.input)} دریافت شد`; - case "invalid_value": - if (issue.values.length === 1) { - return `ورودی نامعتبر: می‌بایست ${stringifyPrimitive(issue.values[0])} می‌بود`; - } - return `گزینه نامعتبر: می‌بایست یکی از ${joinValues(issue.values, "|")} می‌بود`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `خیلی بزرگ: ${issue.origin ?? "مقدار"} باید ${adj}${issue.maximum.toString()} ${sizing.unit ?? "عنصر"} باشد`; - } - return `خیلی بزرگ: ${issue.origin ?? "مقدار"} باید ${adj}${issue.maximum.toString()} باشد`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `خیلی کوچک: ${issue.origin} باید ${adj}${issue.minimum.toString()} ${sizing.unit} باشد`; - } - return `خیلی کوچک: ${issue.origin} باید ${adj}${issue.minimum.toString()} باشد`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `رشته نامعتبر: باید با "${_issue.prefix}" شروع شود`; - } - if (_issue.format === "ends_with") { - return `رشته نامعتبر: باید با "${_issue.suffix}" تمام شود`; - } - if (_issue.format === "includes") { - return `رشته نامعتبر: باید شامل "${_issue.includes}" باشد`; - } - if (_issue.format === "regex") { - return `رشته نامعتبر: باید با الگوی ${_issue.pattern} مطابقت داشته باشد`; - } - return `${Nouns[_issue.format] ?? issue.format} نامعتبر`; - } - case "not_multiple_of": - return `عدد نامعتبر: باید مضرب ${issue.divisor} باشد`; - case "unrecognized_keys": - return `کلید${issue.keys.length > 1 ? "های" : ""} ناشناس: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `کلید ناشناس در ${issue.origin}`; - case "invalid_union": - return `ورودی نامعتبر`; - case "invalid_element": - return `مقدار نامعتبر در ${issue.origin}`; - default: - return `ورودی نامعتبر`; - } - }; -}; -/* harmony default export */ function fa() { - return { - localeError: fa_error(), - }; +function _cuid(Class, params) { + return new Class({ + type: "string", + format: "cuid", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/fi.js - -const fi_error = () => { - const Sizable = { - string: { unit: "merkkiä", subject: "merkkijonon" }, - file: { unit: "tavua", subject: "tiedoston" }, - array: { unit: "alkiota", subject: "listan" }, - set: { unit: "alkiota", subject: "joukon" }, - number: { unit: "", subject: "luvun" }, - bigint: { unit: "", subject: "suuren kokonaisluvun" }, - int: { unit: "", subject: "kokonaisluvun" }, - date: { unit: "", subject: "päivämäärän" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "säännöllinen lauseke", - email: "sähköpostiosoite", - url: "URL-osoite", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO-aikaleima", - date: "ISO-päivämäärä", - time: "ISO-aika", - duration: "ISO-kesto", - ipv4: "IPv4-osoite", - ipv6: "IPv6-osoite", - cidrv4: "IPv4-alue", - cidrv6: "IPv6-alue", - base64: "base64-koodattu merkkijono", - base64url: "base64url-koodattu merkkijono", - json_string: "JSON-merkkijono", - e164: "E.164-luku", - jwt: "JWT", - template_literal: "templaattimerkkijono", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Virheellinen tyyppi: odotettiin ${issue.expected}, oli ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Virheellinen syöte: täytyy olla ${stringifyPrimitive(issue.values[0])}`; - return `Virheellinen valinta: täytyy olla yksi seuraavista: ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Liian suuri: ${sizing.subject} täytyy olla ${adj}${issue.maximum.toString()} ${sizing.unit}`.trim(); - } - return `Liian suuri: arvon täytyy olla ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Liian pieni: ${sizing.subject} täytyy olla ${adj}${issue.minimum.toString()} ${sizing.unit}`.trim(); - } - return `Liian pieni: arvon täytyy olla ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Virheellinen syöte: täytyy alkaa "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Virheellinen syöte: täytyy loppua "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Virheellinen syöte: täytyy sisältää "${_issue.includes}"`; - if (_issue.format === "regex") { - return `Virheellinen syöte: täytyy vastata säännöllistä lauseketta ${_issue.pattern}`; - } - return `Virheellinen ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Virheellinen luku: täytyy olla luvun ${issue.divisor} monikerta`; - case "unrecognized_keys": - return `${issue.keys.length > 1 ? "Tuntemattomat avaimet" : "Tuntematon avain"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return "Virheellinen avain tietueessa"; - case "invalid_union": - return "Virheellinen unioni"; - case "invalid_element": - return "Virheellinen arvo joukossa"; - default: - return `Virheellinen syöte`; - } - }; -}; -/* harmony default export */ function fi() { - return { - localeError: fi_error(), - }; +function _cuid2(Class, params) { + return new Class({ + type: "string", + format: "cuid2", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/fr.js - -const fr_error = () => { - const Sizable = { - string: { unit: "caractères", verb: "avoir" }, - file: { unit: "octets", verb: "avoir" }, - array: { unit: "éléments", verb: "avoir" }, - set: { unit: "éléments", verb: "avoir" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "nombre"; - } - case "object": { - if (Array.isArray(data)) { - return "tableau"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "entrée", - email: "adresse e-mail", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "date et heure ISO", - date: "date ISO", - time: "heure ISO", - duration: "durée ISO", - ipv4: "adresse IPv4", - ipv6: "adresse IPv6", - cidrv4: "plage IPv4", - cidrv6: "plage IPv6", - base64: "chaîne encodée en base64", - base64url: "chaîne encodée en base64url", - json_string: "chaîne JSON", - e164: "numéro E.164", - jwt: "JWT", - template_literal: "entrée", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Entrée invalide : ${issue.expected} attendu, ${parsedType(issue.input)} reçu`; - case "invalid_value": - if (issue.values.length === 1) - return `Entrée invalide : ${stringifyPrimitive(issue.values[0])} attendu`; - return `Option invalide : une valeur parmi ${joinValues(issue.values, "|")} attendue`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Trop grand : ${issue.origin ?? "valeur"} doit ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "élément(s)"}`; - return `Trop grand : ${issue.origin ?? "valeur"} doit être ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Trop petit : ${issue.origin} doit ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Trop petit : ${issue.origin} doit être ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Chaîne invalide : doit commencer par "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Chaîne invalide : doit se terminer par "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Chaîne invalide : doit inclure "${_issue.includes}"`; - if (_issue.format === "regex") - return `Chaîne invalide : doit correspondre au modèle ${_issue.pattern}`; - return `${Nouns[_issue.format] ?? issue.format} invalide`; - } - case "not_multiple_of": - return `Nombre invalide : doit être un multiple de ${issue.divisor}`; - case "unrecognized_keys": - return `Clé${issue.keys.length > 1 ? "s" : ""} non reconnue${issue.keys.length > 1 ? "s" : ""} : ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Clé invalide dans ${issue.origin}`; - case "invalid_union": - return "Entrée invalide"; - case "invalid_element": - return `Valeur invalide dans ${issue.origin}`; - default: - return `Entrée invalide`; - } - }; -}; -/* harmony default export */ function fr() { - return { - localeError: fr_error(), - }; +function _ulid(Class, params) { + return new Class({ + type: "string", + format: "ulid", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/fr-CA.js - -const fr_CA_error = () => { - const Sizable = { - string: { unit: "caractères", verb: "avoir" }, - file: { unit: "octets", verb: "avoir" }, - array: { unit: "éléments", verb: "avoir" }, - set: { unit: "éléments", verb: "avoir" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "entrée", - email: "adresse courriel", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "date-heure ISO", - date: "date ISO", - time: "heure ISO", - duration: "durée ISO", - ipv4: "adresse IPv4", - ipv6: "adresse IPv6", - cidrv4: "plage IPv4", - cidrv6: "plage IPv6", - base64: "chaîne encodée en base64", - base64url: "chaîne encodée en base64url", - json_string: "chaîne JSON", - e164: "numéro E.164", - jwt: "JWT", - template_literal: "entrée", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Entrée invalide : attendu ${issue.expected}, reçu ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Entrée invalide : attendu ${stringifyPrimitive(issue.values[0])}`; - return `Option invalide : attendu l'une des valeurs suivantes ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "≤" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Trop grand : attendu que ${issue.origin ?? "la valeur"} ait ${adj}${issue.maximum.toString()} ${sizing.unit}`; - return `Trop grand : attendu que ${issue.origin ?? "la valeur"} soit ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? "≥" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Trop petit : attendu que ${issue.origin} ait ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Trop petit : attendu que ${issue.origin} soit ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Chaîne invalide : doit commencer par "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `Chaîne invalide : doit se terminer par "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Chaîne invalide : doit inclure "${_issue.includes}"`; - if (_issue.format === "regex") - return `Chaîne invalide : doit correspondre au motif ${_issue.pattern}`; - return `${Nouns[_issue.format] ?? issue.format} invalide`; - } - case "not_multiple_of": - return `Nombre invalide : doit être un multiple de ${issue.divisor}`; - case "unrecognized_keys": - return `Clé${issue.keys.length > 1 ? "s" : ""} non reconnue${issue.keys.length > 1 ? "s" : ""} : ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Clé invalide dans ${issue.origin}`; - case "invalid_union": - return "Entrée invalide"; - case "invalid_element": - return `Valeur invalide dans ${issue.origin}`; - default: - return `Entrée invalide`; - } - }; -}; -/* harmony default export */ function fr_CA() { - return { - localeError: fr_CA_error(), - }; +function _xid(Class, params) { + return new Class({ + type: "string", + format: "xid", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/he.js - -const he_error = () => { - // Hebrew labels + grammatical gender - const TypeNames = { - string: { label: "מחרוזת", gender: "f" }, - number: { label: "מספר", gender: "m" }, - boolean: { label: "ערך בוליאני", gender: "m" }, - bigint: { label: "BigInt", gender: "m" }, - date: { label: "תאריך", gender: "m" }, - array: { label: "מערך", gender: "m" }, - object: { label: "אובייקט", gender: "m" }, - null: { label: "ערך ריק (null)", gender: "m" }, - undefined: { label: "ערך לא מוגדר (undefined)", gender: "m" }, - symbol: { label: "סימבול (Symbol)", gender: "m" }, - function: { label: "פונקציה", gender: "f" }, - map: { label: "מפה (Map)", gender: "f" }, - set: { label: "קבוצה (Set)", gender: "f" }, - file: { label: "קובץ", gender: "m" }, - promise: { label: "Promise", gender: "m" }, - NaN: { label: "NaN", gender: "m" }, - unknown: { label: "ערך לא ידוע", gender: "m" }, - value: { label: "ערך", gender: "m" }, - }; - // Sizing units for size-related messages + localized origin labels - const Sizable = { - string: { unit: "תווים", shortLabel: "קצר", longLabel: "ארוך" }, - file: { unit: "בייטים", shortLabel: "קטן", longLabel: "גדול" }, - array: { unit: "פריטים", shortLabel: "קטן", longLabel: "גדול" }, - set: { unit: "פריטים", shortLabel: "קטן", longLabel: "גדול" }, - number: { unit: "", shortLabel: "קטן", longLabel: "גדול" }, // no unit - }; - // Helpers — labels, articles, and verbs - const typeEntry = (t) => (t ? TypeNames[t] : undefined); - const typeLabel = (t) => { - const e = typeEntry(t); - if (e) - return e.label; - // fallback: show raw string if unknown - return t ?? TypeNames.unknown.label; - }; - const withDefinite = (t) => `ה${typeLabel(t)}`; - const verbFor = (t) => { - const e = typeEntry(t); - const gender = e?.gender ?? "m"; - return gender === "f" ? "צריכה להיות" : "צריך להיות"; - }; - const getSizing = (origin) => { - if (!origin) - return null; - return Sizable[origin] ?? null; - }; - // Robust type parser for "received" — returns a key we understand or a constructor name - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": - return Number.isNaN(data) ? "NaN" : "number"; - case "object": { - if (Array.isArray(data)) - return "array"; - if (data === null) - return "null"; - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; // keep as-is (e.g., "Date") - } - return "object"; - } - default: - return t; - } - }; - const Nouns = { - regex: { label: "קלט", gender: "m" }, - email: { label: "כתובת אימייל", gender: "f" }, - url: { label: "כתובת רשת", gender: "f" }, - emoji: { label: "אימוג'י", gender: "m" }, - uuid: { label: "UUID", gender: "m" }, - nanoid: { label: "nanoid", gender: "m" }, - guid: { label: "GUID", gender: "m" }, - cuid: { label: "cuid", gender: "m" }, - cuid2: { label: "cuid2", gender: "m" }, - ulid: { label: "ULID", gender: "m" }, - xid: { label: "XID", gender: "m" }, - ksuid: { label: "KSUID", gender: "m" }, - datetime: { label: "תאריך וזמן ISO", gender: "m" }, - date: { label: "תאריך ISO", gender: "m" }, - time: { label: "זמן ISO", gender: "m" }, - duration: { label: "משך זמן ISO", gender: "m" }, - ipv4: { label: "כתובת IPv4", gender: "f" }, - ipv6: { label: "כתובת IPv6", gender: "f" }, - cidrv4: { label: "טווח IPv4", gender: "m" }, - cidrv6: { label: "טווח IPv6", gender: "m" }, - base64: { label: "מחרוזת בבסיס 64", gender: "f" }, - base64url: { label: "מחרוזת בבסיס 64 לכתובות רשת", gender: "f" }, - json_string: { label: "מחרוזת JSON", gender: "f" }, - e164: { label: "מספר E.164", gender: "m" }, - jwt: { label: "JWT", gender: "m" }, - ends_with: { label: "קלט", gender: "m" }, - includes: { label: "קלט", gender: "m" }, - lowercase: { label: "קלט", gender: "m" }, - starts_with: { label: "קלט", gender: "m" }, - uppercase: { label: "קלט", gender: "m" }, - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": { - // Expected type: show without definite article for clearer Hebrew - const expectedKey = issue.expected; - const expected = typeLabel(expectedKey); - // Received: show localized label if known, otherwise constructor/raw - const receivedKey = parsedType(issue.input); - const received = TypeNames[receivedKey]?.label ?? receivedKey; - return `קלט לא תקין: צריך להיות ${expected}, התקבל ${received}`; - } - case "invalid_value": { - if (issue.values.length === 1) { - return `ערך לא תקין: הערך חייב להיות ${stringifyPrimitive(issue.values[0])}`; - } - // Join values with proper Hebrew formatting - const stringified = issue.values.map((v) => stringifyPrimitive(v)); - if (issue.values.length === 2) { - return `ערך לא תקין: האפשרויות המתאימות הן ${stringified[0]} או ${stringified[1]}`; - } - // For 3+ values: "a", "b" או "c" - const lastValue = stringified[stringified.length - 1]; - const restValues = stringified.slice(0, -1).join(", "); - return `ערך לא תקין: האפשרויות המתאימות הן ${restValues} או ${lastValue}`; - } - case "too_big": { - const sizing = getSizing(issue.origin); - const subject = withDefinite(issue.origin ?? "value"); - if (issue.origin === "string") { - // Special handling for strings - more natural Hebrew - return `${sizing?.longLabel ?? "ארוך"} מדי: ${subject} צריכה להכיל ${issue.maximum.toString()} ${sizing?.unit ?? ""} ${issue.inclusive ? "או פחות" : "לכל היותר"}`.trim(); - } - if (issue.origin === "number") { - // Natural Hebrew for numbers - const comparison = issue.inclusive ? `קטן או שווה ל-${issue.maximum}` : `קטן מ-${issue.maximum}`; - return `גדול מדי: ${subject} צריך להיות ${comparison}`; - } - if (issue.origin === "array" || issue.origin === "set") { - // Natural Hebrew for arrays and sets - const verb = issue.origin === "set" ? "צריכה" : "צריך"; - const comparison = issue.inclusive - ? `${issue.maximum} ${sizing?.unit ?? ""} או פחות` - : `פחות מ-${issue.maximum} ${sizing?.unit ?? ""}`; - return `גדול מדי: ${subject} ${verb} להכיל ${comparison}`.trim(); - } - const adj = issue.inclusive ? "<=" : "<"; - const be = verbFor(issue.origin ?? "value"); - if (sizing?.unit) { - return `${sizing.longLabel} מדי: ${subject} ${be} ${adj}${issue.maximum.toString()} ${sizing.unit}`; - } - return `${sizing?.longLabel ?? "גדול"} מדי: ${subject} ${be} ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const sizing = getSizing(issue.origin); - const subject = withDefinite(issue.origin ?? "value"); - if (issue.origin === "string") { - // Special handling for strings - more natural Hebrew - return `${sizing?.shortLabel ?? "קצר"} מדי: ${subject} צריכה להכיל ${issue.minimum.toString()} ${sizing?.unit ?? ""} ${issue.inclusive ? "או יותר" : "לפחות"}`.trim(); - } - if (issue.origin === "number") { - // Natural Hebrew for numbers - const comparison = issue.inclusive ? `גדול או שווה ל-${issue.minimum}` : `גדול מ-${issue.minimum}`; - return `קטן מדי: ${subject} צריך להיות ${comparison}`; - } - if (issue.origin === "array" || issue.origin === "set") { - // Natural Hebrew for arrays and sets - const verb = issue.origin === "set" ? "צריכה" : "צריך"; - // Special case for singular (minimum === 1) - if (issue.minimum === 1 && issue.inclusive) { - const singularPhrase = issue.origin === "set" ? "לפחות פריט אחד" : "לפחות פריט אחד"; - return `קטן מדי: ${subject} ${verb} להכיל ${singularPhrase}`; - } - const comparison = issue.inclusive - ? `${issue.minimum} ${sizing?.unit ?? ""} או יותר` - : `יותר מ-${issue.minimum} ${sizing?.unit ?? ""}`; - return `קטן מדי: ${subject} ${verb} להכיל ${comparison}`.trim(); - } - const adj = issue.inclusive ? ">=" : ">"; - const be = verbFor(issue.origin ?? "value"); - if (sizing?.unit) { - return `${sizing.shortLabel} מדי: ${subject} ${be} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `${sizing?.shortLabel ?? "קטן"} מדי: ${subject} ${be} ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - // These apply to strings — use feminine grammar + ה׳ הידיעה - if (_issue.format === "starts_with") - return `המחרוזת חייבת להתחיל ב "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `המחרוזת חייבת להסתיים ב "${_issue.suffix}"`; - if (_issue.format === "includes") - return `המחרוזת חייבת לכלול "${_issue.includes}"`; - if (_issue.format === "regex") - return `המחרוזת חייבת להתאים לתבנית ${_issue.pattern}`; - // Handle gender agreement for formats - const nounEntry = Nouns[_issue.format]; - const noun = nounEntry?.label ?? _issue.format; - const gender = nounEntry?.gender ?? "m"; - const adjective = gender === "f" ? "תקינה" : "תקין"; - return `${noun} לא ${adjective}`; - } - case "not_multiple_of": - return `מספר לא תקין: חייב להיות מכפלה של ${issue.divisor}`; - case "unrecognized_keys": - return `מפתח${issue.keys.length > 1 ? "ות" : ""} לא מזוה${issue.keys.length > 1 ? "ים" : "ה"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": { - return `שדה לא תקין באובייקט`; - } - case "invalid_union": - return "קלט לא תקין"; - case "invalid_element": { - const place = withDefinite(issue.origin ?? "array"); - return `ערך לא תקין ב${place}`; - } - default: - return `קלט לא תקין`; - } - }; -}; -/* harmony default export */ function he() { - return { - localeError: he_error(), - }; +function _ksuid(Class, params) { + return new Class({ + type: "string", + format: "ksuid", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/hu.js - -const hu_error = () => { - const Sizable = { - string: { unit: "karakter", verb: "legyen" }, - file: { unit: "byte", verb: "legyen" }, - array: { unit: "elem", verb: "legyen" }, - set: { unit: "elem", verb: "legyen" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "szám"; - } - case "object": { - if (Array.isArray(data)) { - return "tömb"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "bemenet", - email: "email cím", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO időbélyeg", - date: "ISO dátum", - time: "ISO idő", - duration: "ISO időintervallum", - ipv4: "IPv4 cím", - ipv6: "IPv6 cím", - cidrv4: "IPv4 tartomány", - cidrv6: "IPv6 tartomány", - base64: "base64-kódolt string", - base64url: "base64url-kódolt string", - json_string: "JSON string", - e164: "E.164 szám", - jwt: "JWT", - template_literal: "bemenet", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Érvénytelen bemenet: a várt érték ${issue.expected}, a kapott érték ${parsedType(issue.input)}`; - // return `Invalid input: expected ${issue.expected}, received ${util.getParsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Érvénytelen bemenet: a várt érték ${stringifyPrimitive(issue.values[0])}`; - return `Érvénytelen opció: valamelyik érték várt ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Túl nagy: ${issue.origin ?? "érték"} mérete túl nagy ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elem"}`; - return `Túl nagy: a bemeneti érték ${issue.origin ?? "érték"} túl nagy: ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Túl kicsi: a bemeneti érték ${issue.origin} mérete túl kicsi ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Túl kicsi: a bemeneti érték ${issue.origin} túl kicsi ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Érvénytelen string: "${_issue.prefix}" értékkel kell kezdődnie`; - if (_issue.format === "ends_with") - return `Érvénytelen string: "${_issue.suffix}" értékkel kell végződnie`; - if (_issue.format === "includes") - return `Érvénytelen string: "${_issue.includes}" értéket kell tartalmaznia`; - if (_issue.format === "regex") - return `Érvénytelen string: ${_issue.pattern} mintának kell megfelelnie`; - return `Érvénytelen ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Érvénytelen szám: ${issue.divisor} többszörösének kell lennie`; - case "unrecognized_keys": - return `Ismeretlen kulcs${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Érvénytelen kulcs ${issue.origin}`; - case "invalid_union": - return "Érvénytelen bemenet"; - case "invalid_element": - return `Érvénytelen érték: ${issue.origin}`; - default: - return `Érvénytelen bemenet`; - } - }; -}; -/* harmony default export */ function hu() { - return { - localeError: hu_error(), - }; +function _ipv4(Class, params) { + return new Class({ + type: "string", + format: "ipv4", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/id.js - -const id_error = () => { - const Sizable = { - string: { unit: "karakter", verb: "memiliki" }, - file: { unit: "byte", verb: "memiliki" }, - array: { unit: "item", verb: "memiliki" }, - set: { unit: "item", verb: "memiliki" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "input", - email: "alamat email", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "tanggal dan waktu format ISO", - date: "tanggal format ISO", - time: "jam format ISO", - duration: "durasi format ISO", - ipv4: "alamat IPv4", - ipv6: "alamat IPv6", - cidrv4: "rentang alamat IPv4", - cidrv6: "rentang alamat IPv6", - base64: "string dengan enkode base64", - base64url: "string dengan enkode base64url", - json_string: "string JSON", - e164: "angka E.164", - jwt: "JWT", - template_literal: "input", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Input tidak valid: diharapkan ${issue.expected}, diterima ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Input tidak valid: diharapkan ${stringifyPrimitive(issue.values[0])}`; - return `Pilihan tidak valid: diharapkan salah satu dari ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Terlalu besar: diharapkan ${issue.origin ?? "value"} memiliki ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elemen"}`; - return `Terlalu besar: diharapkan ${issue.origin ?? "value"} menjadi ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Terlalu kecil: diharapkan ${issue.origin} memiliki ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Terlalu kecil: diharapkan ${issue.origin} menjadi ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `String tidak valid: harus dimulai dengan "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `String tidak valid: harus berakhir dengan "${_issue.suffix}"`; - if (_issue.format === "includes") - return `String tidak valid: harus menyertakan "${_issue.includes}"`; - if (_issue.format === "regex") - return `String tidak valid: harus sesuai pola ${_issue.pattern}`; - return `${Nouns[_issue.format] ?? issue.format} tidak valid`; - } - case "not_multiple_of": - return `Angka tidak valid: harus kelipatan dari ${issue.divisor}`; - case "unrecognized_keys": - return `Kunci tidak dikenali ${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Kunci tidak valid di ${issue.origin}`; - case "invalid_union": - return "Input tidak valid"; - case "invalid_element": - return `Nilai tidak valid di ${issue.origin}`; - default: - return `Input tidak valid`; - } - }; -}; -/* harmony default export */ function id() { - return { - localeError: id_error(), - }; +function _ipv6(Class, params) { + return new Class({ + type: "string", + format: "ipv6", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/is.js - -const is_parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "númer"; - } - case "object": { - if (Array.isArray(data)) { - return "fylki"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; -}; -const is_error = () => { - const Sizable = { - string: { unit: "stafi", verb: "að hafa" }, - file: { unit: "bæti", verb: "að hafa" }, - array: { unit: "hluti", verb: "að hafa" }, - set: { unit: "hluti", verb: "að hafa" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const Nouns = { - regex: "gildi", - email: "netfang", - url: "vefslóð", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO dagsetning og tími", - date: "ISO dagsetning", - time: "ISO tími", - duration: "ISO tímalengd", - ipv4: "IPv4 address", - ipv6: "IPv6 address", - cidrv4: "IPv4 range", - cidrv6: "IPv6 range", - base64: "base64-encoded strengur", - base64url: "base64url-encoded strengur", - json_string: "JSON strengur", - e164: "E.164 tölugildi", - jwt: "JWT", - template_literal: "gildi", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Rangt gildi: Þú slóst inn ${is_parsedType(issue.input)} þar sem á að vera ${issue.expected}`; - case "invalid_value": - if (issue.values.length === 1) - return `Rangt gildi: gert ráð fyrir ${stringifyPrimitive(issue.values[0])}`; - return `Ógilt val: má vera eitt af eftirfarandi ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Of stórt: gert er ráð fyrir að ${issue.origin ?? "gildi"} hafi ${adj}${issue.maximum.toString()} ${sizing.unit ?? "hluti"}`; - return `Of stórt: gert er ráð fyrir að ${issue.origin ?? "gildi"} sé ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Of lítið: gert er ráð fyrir að ${issue.origin} hafi ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Of lítið: gert er ráð fyrir að ${issue.origin} sé ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Ógildur strengur: verður að byrja á "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `Ógildur strengur: verður að enda á "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Ógildur strengur: verður að innihalda "${_issue.includes}"`; - if (_issue.format === "regex") - return `Ógildur strengur: verður að fylgja mynstri ${_issue.pattern}`; - return `Rangt ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Röng tala: verður að vera margfeldi af ${issue.divisor}`; - case "unrecognized_keys": - return `Óþekkt ${issue.keys.length > 1 ? "ir lyklar" : "ur lykill"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Rangur lykill í ${issue.origin}`; - case "invalid_union": - return "Rangt gildi"; - case "invalid_element": - return `Rangt gildi í ${issue.origin}`; - default: - return `Rangt gildi`; - } - }; -}; -/* harmony default export */ function is() { - return { - localeError: is_error(), - }; +function _cidrv4(Class, params) { + return new Class({ + type: "string", + format: "cidrv4", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/it.js - -const it_error = () => { - const Sizable = { - string: { unit: "caratteri", verb: "avere" }, - file: { unit: "byte", verb: "avere" }, - array: { unit: "elementi", verb: "avere" }, - set: { unit: "elementi", verb: "avere" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "numero"; - } - case "object": { - if (Array.isArray(data)) { - return "vettore"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "input", - email: "indirizzo email", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "data e ora ISO", - date: "data ISO", - time: "ora ISO", - duration: "durata ISO", - ipv4: "indirizzo IPv4", - ipv6: "indirizzo IPv6", - cidrv4: "intervallo IPv4", - cidrv6: "intervallo IPv6", - base64: "stringa codificata in base64", - base64url: "URL codificata in base64", - json_string: "stringa JSON", - e164: "numero E.164", - jwt: "JWT", - template_literal: "input", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Input non valido: atteso ${issue.expected}, ricevuto ${parsedType(issue.input)}`; - // return `Input non valido: atteso ${issue.expected}, ricevuto ${util.getParsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Input non valido: atteso ${stringifyPrimitive(issue.values[0])}`; - return `Opzione non valida: atteso uno tra ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Troppo grande: ${issue.origin ?? "valore"} deve avere ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementi"}`; - return `Troppo grande: ${issue.origin ?? "valore"} deve essere ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Troppo piccolo: ${issue.origin} deve avere ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Troppo piccolo: ${issue.origin} deve essere ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Stringa non valida: deve iniziare con "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Stringa non valida: deve terminare con "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Stringa non valida: deve includere "${_issue.includes}"`; - if (_issue.format === "regex") - return `Stringa non valida: deve corrispondere al pattern ${_issue.pattern}`; - return `Invalid ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Numero non valido: deve essere un multiplo di ${issue.divisor}`; - case "unrecognized_keys": - return `Chiav${issue.keys.length > 1 ? "i" : "e"} non riconosciut${issue.keys.length > 1 ? "e" : "a"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Chiave non valida in ${issue.origin}`; - case "invalid_union": - return "Input non valido"; - case "invalid_element": - return `Valore non valido in ${issue.origin}`; - default: - return `Input non valido`; - } - }; -}; -/* harmony default export */ function it() { - return { - localeError: it_error(), - }; +function _cidrv6(Class, params) { + return new Class({ + type: "string", + format: "cidrv6", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ja.js - -const ja_error = () => { - const Sizable = { - string: { unit: "文字", verb: "である" }, - file: { unit: "バイト", verb: "である" }, - array: { unit: "要素", verb: "である" }, - set: { unit: "要素", verb: "である" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "数値"; - } - case "object": { - if (Array.isArray(data)) { - return "配列"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "入力値", - email: "メールアドレス", - url: "URL", - emoji: "絵文字", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO日時", - date: "ISO日付", - time: "ISO時刻", - duration: "ISO期間", - ipv4: "IPv4アドレス", - ipv6: "IPv6アドレス", - cidrv4: "IPv4範囲", - cidrv6: "IPv6範囲", - base64: "base64エンコード文字列", - base64url: "base64urlエンコード文字列", - json_string: "JSON文字列", - e164: "E.164番号", - jwt: "JWT", - template_literal: "入力値", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `無効な入力: ${issue.expected}が期待されましたが、${parsedType(issue.input)}が入力されました`; - case "invalid_value": - if (issue.values.length === 1) - return `無効な入力: ${stringifyPrimitive(issue.values[0])}が期待されました`; - return `無効な選択: ${joinValues(issue.values, "、")}のいずれかである必要があります`; - case "too_big": { - const adj = issue.inclusive ? "以下である" : "より小さい"; - const sizing = getSizing(issue.origin); - if (sizing) - return `大きすぎる値: ${issue.origin ?? "値"}は${issue.maximum.toString()}${sizing.unit ?? "要素"}${adj}必要があります`; - return `大きすぎる値: ${issue.origin ?? "値"}は${issue.maximum.toString()}${adj}必要があります`; - } - case "too_small": { - const adj = issue.inclusive ? "以上である" : "より大きい"; - const sizing = getSizing(issue.origin); - if (sizing) - return `小さすぎる値: ${issue.origin}は${issue.minimum.toString()}${sizing.unit}${adj}必要があります`; - return `小さすぎる値: ${issue.origin}は${issue.minimum.toString()}${adj}必要があります`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `無効な文字列: "${_issue.prefix}"で始まる必要があります`; - if (_issue.format === "ends_with") - return `無効な文字列: "${_issue.suffix}"で終わる必要があります`; - if (_issue.format === "includes") - return `無効な文字列: "${_issue.includes}"を含む必要があります`; - if (_issue.format === "regex") - return `無効な文字列: パターン${_issue.pattern}に一致する必要があります`; - return `無効な${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `無効な数値: ${issue.divisor}の倍数である必要があります`; - case "unrecognized_keys": - return `認識されていないキー${issue.keys.length > 1 ? "群" : ""}: ${joinValues(issue.keys, "、")}`; - case "invalid_key": - return `${issue.origin}内の無効なキー`; - case "invalid_union": - return "無効な入力"; - case "invalid_element": - return `${issue.origin}内の無効な値`; - default: - return `無効な入力`; - } - }; -}; -/* harmony default export */ function ja() { - return { - localeError: ja_error(), - }; +function _base64(Class, params) { + return new Class({ + type: "string", + format: "base64", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ka.js - -const ka_parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "რიცხვი"; - } - case "object": { - if (Array.isArray(data)) { - return "მასივი"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - const typeMap = { - string: "სტრინგი", - boolean: "ბულეანი", - undefined: "undefined", - bigint: "bigint", - symbol: "symbol", - function: "ფუნქცია", - }; - return typeMap[t] ?? t; -}; -const ka_error = () => { - const Sizable = { - string: { unit: "სიმბოლო", verb: "უნდა შეიცავდეს" }, - file: { unit: "ბაიტი", verb: "უნდა შეიცავდეს" }, - array: { unit: "ელემენტი", verb: "უნდა შეიცავდეს" }, - set: { unit: "ელემენტი", verb: "უნდა შეიცავდეს" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const Nouns = { - regex: "შეყვანა", - email: "ელ-ფოსტის მისამართი", - url: "URL", - emoji: "ემოჯი", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "თარიღი-დრო", - date: "თარიღი", - time: "დრო", - duration: "ხანგრძლივობა", - ipv4: "IPv4 მისამართი", - ipv6: "IPv6 მისამართი", - cidrv4: "IPv4 დიაპაზონი", - cidrv6: "IPv6 დიაპაზონი", - base64: "base64-კოდირებული სტრინგი", - base64url: "base64url-კოდირებული სტრინგი", - json_string: "JSON სტრინგი", - e164: "E.164 ნომერი", - jwt: "JWT", - template_literal: "შეყვანა", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `არასწორი შეყვანა: მოსალოდნელი ${issue.expected}, მიღებული ${ka_parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `არასწორი შეყვანა: მოსალოდნელი ${stringifyPrimitive(issue.values[0])}`; - return `არასწორი ვარიანტი: მოსალოდნელია ერთ-ერთი ${joinValues(issue.values, "|")}-დან`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `ზედმეტად დიდი: მოსალოდნელი ${issue.origin ?? "მნიშვნელობა"} ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit}`; - return `ზედმეტად დიდი: მოსალოდნელი ${issue.origin ?? "მნიშვნელობა"} იყოს ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `ზედმეტად პატარა: მოსალოდნელი ${issue.origin} ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `ზედმეტად პატარა: მოსალოდნელი ${issue.origin} იყოს ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `არასწორი სტრინგი: უნდა იწყებოდეს "${_issue.prefix}"-ით`; - } - if (_issue.format === "ends_with") - return `არასწორი სტრინგი: უნდა მთავრდებოდეს "${_issue.suffix}"-ით`; - if (_issue.format === "includes") - return `არასწორი სტრინგი: უნდა შეიცავდეს "${_issue.includes}"-ს`; - if (_issue.format === "regex") - return `არასწორი სტრინგი: უნდა შეესაბამებოდეს შაბლონს ${_issue.pattern}`; - return `არასწორი ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `არასწორი რიცხვი: უნდა იყოს ${issue.divisor}-ის ჯერადი`; - case "unrecognized_keys": - return `უცნობი გასაღებ${issue.keys.length > 1 ? "ები" : "ი"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `არასწორი გასაღები ${issue.origin}-ში`; - case "invalid_union": - return "არასწორი შეყვანა"; - case "invalid_element": - return `არასწორი მნიშვნელობა ${issue.origin}-ში`; - default: - return `არასწორი შეყვანა`; - } - }; -}; -/* harmony default export */ function ka() { - return { - localeError: ka_error(), - }; +function _base64url(Class, params) { + return new Class({ + type: "string", + format: "base64url", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/km.js - -const km_error = () => { - const Sizable = { - string: { unit: "តួអក្សរ", verb: "គួរមាន" }, - file: { unit: "បៃ", verb: "គួរមាន" }, - array: { unit: "ធាតុ", verb: "គួរមាន" }, - set: { unit: "ធាតុ", verb: "គួរមាន" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "មិនមែនជាលេខ (NaN)" : "លេខ"; - } - case "object": { - if (Array.isArray(data)) { - return "អារេ (Array)"; - } - if (data === null) { - return "គ្មានតម្លៃ (null)"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "ទិន្នន័យបញ្ចូល", - email: "អាសយដ្ឋានអ៊ីមែល", - url: "URL", - emoji: "សញ្ញាអារម្មណ៍", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "កាលបរិច្ឆេទ និងម៉ោង ISO", - date: "កាលបរិច្ឆេទ ISO", - time: "ម៉ោង ISO", - duration: "រយៈពេល ISO", - ipv4: "អាសយដ្ឋាន IPv4", - ipv6: "អាសយដ្ឋាន IPv6", - cidrv4: "ដែនអាសយដ្ឋាន IPv4", - cidrv6: "ដែនអាសយដ្ឋាន IPv6", - base64: "ខ្សែអក្សរអ៊ិកូដ base64", - base64url: "ខ្សែអក្សរអ៊ិកូដ base64url", - json_string: "ខ្សែអក្សរ JSON", - e164: "លេខ E.164", - jwt: "JWT", - template_literal: "ទិន្នន័យបញ្ចូល", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `ទិន្នន័យបញ្ចូលមិនត្រឹមត្រូវ៖ ត្រូវការ ${issue.expected} ប៉ុន្តែទទួលបាន ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `ទិន្នន័យបញ្ចូលមិនត្រឹមត្រូវ៖ ត្រូវការ ${stringifyPrimitive(issue.values[0])}`; - return `ជម្រើសមិនត្រឹមត្រូវ៖ ត្រូវជាមួយក្នុងចំណោម ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `ធំពេក៖ ត្រូវការ ${issue.origin ?? "តម្លៃ"} ${adj} ${issue.maximum.toString()} ${sizing.unit ?? "ធាតុ"}`; - return `ធំពេក៖ ត្រូវការ ${issue.origin ?? "តម្លៃ"} ${adj} ${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `តូចពេក៖ ត្រូវការ ${issue.origin} ${adj} ${issue.minimum.toString()} ${sizing.unit}`; - } - return `តូចពេក៖ ត្រូវការ ${issue.origin} ${adj} ${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `ខ្សែអក្សរមិនត្រឹមត្រូវ៖ ត្រូវចាប់ផ្តើមដោយ "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `ខ្សែអក្សរមិនត្រឹមត្រូវ៖ ត្រូវបញ្ចប់ដោយ "${_issue.suffix}"`; - if (_issue.format === "includes") - return `ខ្សែអក្សរមិនត្រឹមត្រូវ៖ ត្រូវមាន "${_issue.includes}"`; - if (_issue.format === "regex") - return `ខ្សែអក្សរមិនត្រឹមត្រូវ៖ ត្រូវតែផ្គូផ្គងនឹងទម្រង់ដែលបានកំណត់ ${_issue.pattern}`; - return `មិនត្រឹមត្រូវ៖ ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `លេខមិនត្រឹមត្រូវ៖ ត្រូវតែជាពហុគុណនៃ ${issue.divisor}`; - case "unrecognized_keys": - return `រកឃើញសោមិនស្គាល់៖ ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `សោមិនត្រឹមត្រូវនៅក្នុង ${issue.origin}`; - case "invalid_union": - return `ទិន្នន័យមិនត្រឹមត្រូវ`; - case "invalid_element": - return `ទិន្នន័យមិនត្រឹមត្រូវនៅក្នុង ${issue.origin}`; - default: - return `ទិន្នន័យមិនត្រឹមត្រូវ`; - } - }; -}; -/* harmony default export */ function km() { - return { - localeError: km_error(), - }; +function _e164(Class, params) { + return new Class({ + type: "string", + format: "e164", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/kh.js - -/** @deprecated Use `km` instead. */ -/* harmony default export */ function kh() { - return km(); +function _jwt(Class, params) { + return new Class({ + type: "string", + format: "jwt", + check: "string_format", + abort: false, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ko.js - -const ko_error = () => { - const Sizable = { - string: { unit: "문자", verb: "to have" }, - file: { unit: "바이트", verb: "to have" }, - array: { unit: "개", verb: "to have" }, - set: { unit: "개", verb: "to have" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "입력", - email: "이메일 주소", - url: "URL", - emoji: "이모지", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO 날짜시간", - date: "ISO 날짜", - time: "ISO 시간", - duration: "ISO 기간", - ipv4: "IPv4 주소", - ipv6: "IPv6 주소", - cidrv4: "IPv4 범위", - cidrv6: "IPv6 범위", - base64: "base64 인코딩 문자열", - base64url: "base64url 인코딩 문자열", - json_string: "JSON 문자열", - e164: "E.164 번호", - jwt: "JWT", - template_literal: "입력", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `잘못된 입력: 예상 타입은 ${issue.expected}, 받은 타입은 ${parsedType(issue.input)}입니다`; - case "invalid_value": - if (issue.values.length === 1) - return `잘못된 입력: 값은 ${stringifyPrimitive(issue.values[0])} 이어야 합니다`; - return `잘못된 옵션: ${joinValues(issue.values, "또는 ")} 중 하나여야 합니다`; - case "too_big": { - const adj = issue.inclusive ? "이하" : "미만"; - const suffix = adj === "미만" ? "이어야 합니다" : "여야 합니다"; - const sizing = getSizing(issue.origin); - const unit = sizing?.unit ?? "요소"; - if (sizing) - return `${issue.origin ?? "값"}이 너무 큽니다: ${issue.maximum.toString()}${unit} ${adj}${suffix}`; - return `${issue.origin ?? "값"}이 너무 큽니다: ${issue.maximum.toString()} ${adj}${suffix}`; - } - case "too_small": { - const adj = issue.inclusive ? "이상" : "초과"; - const suffix = adj === "이상" ? "이어야 합니다" : "여야 합니다"; - const sizing = getSizing(issue.origin); - const unit = sizing?.unit ?? "요소"; - if (sizing) { - return `${issue.origin ?? "값"}이 너무 작습니다: ${issue.minimum.toString()}${unit} ${adj}${suffix}`; - } - return `${issue.origin ?? "값"}이 너무 작습니다: ${issue.minimum.toString()} ${adj}${suffix}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `잘못된 문자열: "${_issue.prefix}"(으)로 시작해야 합니다`; - } - if (_issue.format === "ends_with") - return `잘못된 문자열: "${_issue.suffix}"(으)로 끝나야 합니다`; - if (_issue.format === "includes") - return `잘못된 문자열: "${_issue.includes}"을(를) 포함해야 합니다`; - if (_issue.format === "regex") - return `잘못된 문자열: 정규식 ${_issue.pattern} 패턴과 일치해야 합니다`; - return `잘못된 ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `잘못된 숫자: ${issue.divisor}의 배수여야 합니다`; - case "unrecognized_keys": - return `인식할 수 없는 키: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `잘못된 키: ${issue.origin}`; - case "invalid_union": - return `잘못된 입력`; - case "invalid_element": - return `잘못된 값: ${issue.origin}`; - default: - return `잘못된 입력`; - } - }; +const TimePrecision = { + Any: null, + Minute: -1, + Second: 0, + Millisecond: 3, + Microsecond: 6, }; -/* harmony default export */ function ko() { - return { - localeError: ko_error(), - }; +function _isoDateTime(Class, params) { + return new Class({ + type: "string", + format: "datetime", + check: "string_format", + offset: false, + local: false, + precision: null, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/lt.js - -const lt_parsedType = (data) => { - const t = typeof data; - return parsedTypeFromType(t, data); -}; -const parsedTypeFromType = (t, data = undefined) => { - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "skaičius"; - } - case "bigint": { - return "sveikasis skaičius"; - } - case "string": { - return "eilutė"; - } - case "boolean": { - return "loginė reikšmė"; - } - case "undefined": - case "void": { - return "neapibrėžta reikšmė"; - } - case "function": { - return "funkcija"; - } - case "symbol": { - return "simbolis"; - } - case "object": { - if (data === undefined) - return "nežinomas objektas"; - if (data === null) - return "nulinė reikšmė"; - if (Array.isArray(data)) - return "masyvas"; - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - return "objektas"; - } - //Zod types below - case "null": { - return "nulinė reikšmė"; - } - } - return t; -}; -const capitalizeFirstCharacter = (text) => { - return text.charAt(0).toUpperCase() + text.slice(1); -}; -function getUnitTypeFromNumber(number) { - const abs = Math.abs(number); - const last = abs % 10; - const last2 = abs % 100; - if ((last2 >= 11 && last2 <= 19) || last === 0) - return "many"; - if (last === 1) - return "one"; - return "few"; -} -const lt_error = () => { - const Sizable = { - string: { - unit: { - one: "simbolis", - few: "simboliai", - many: "simbolių", - }, - verb: { - smaller: { - inclusive: "turi būti ne ilgesnė kaip", - notInclusive: "turi būti trumpesnė kaip", - }, - bigger: { - inclusive: "turi būti ne trumpesnė kaip", - notInclusive: "turi būti ilgesnė kaip", - }, - }, - }, - file: { - unit: { - one: "baitas", - few: "baitai", - many: "baitų", - }, - verb: { - smaller: { - inclusive: "turi būti ne didesnis kaip", - notInclusive: "turi būti mažesnis kaip", - }, - bigger: { - inclusive: "turi būti ne mažesnis kaip", - notInclusive: "turi būti didesnis kaip", - }, - }, - }, - array: { - unit: { - one: "elementą", - few: "elementus", - many: "elementų", - }, - verb: { - smaller: { - inclusive: "turi turėti ne daugiau kaip", - notInclusive: "turi turėti mažiau kaip", - }, - bigger: { - inclusive: "turi turėti ne mažiau kaip", - notInclusive: "turi turėti daugiau kaip", - }, - }, - }, - set: { - unit: { - one: "elementą", - few: "elementus", - many: "elementų", - }, - verb: { - smaller: { - inclusive: "turi turėti ne daugiau kaip", - notInclusive: "turi turėti mažiau kaip", - }, - bigger: { - inclusive: "turi turėti ne mažiau kaip", - notInclusive: "turi turėti daugiau kaip", - }, - }, - }, - }; - function getSizing(origin, unitType, inclusive, targetShouldBe) { - const result = Sizable[origin] ?? null; - if (result === null) - return result; - return { - unit: result.unit[unitType], - verb: result.verb[targetShouldBe][inclusive ? "inclusive" : "notInclusive"], - }; - } - const Nouns = { - regex: "įvestis", - email: "el. pašto adresas", - url: "URL", - emoji: "jaustukas", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO data ir laikas", - date: "ISO data", - time: "ISO laikas", - duration: "ISO trukmė", - ipv4: "IPv4 adresas", - ipv6: "IPv6 adresas", - cidrv4: "IPv4 tinklo prefiksas (CIDR)", - cidrv6: "IPv6 tinklo prefiksas (CIDR)", - base64: "base64 užkoduota eilutė", - base64url: "base64url užkoduota eilutė", - json_string: "JSON eilutė", - e164: "E.164 numeris", - jwt: "JWT", - template_literal: "įvestis", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Gautas tipas ${lt_parsedType(issue.input)}, o tikėtasi - ${parsedTypeFromType(issue.expected)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Privalo būti ${stringifyPrimitive(issue.values[0])}`; - return `Privalo būti vienas iš ${joinValues(issue.values, "|")} pasirinkimų`; - case "too_big": { - const origin = parsedTypeFromType(issue.origin); - const sizing = getSizing(issue.origin, getUnitTypeFromNumber(Number(issue.maximum)), issue.inclusive ?? false, "smaller"); - if (sizing?.verb) - return `${capitalizeFirstCharacter(origin ?? issue.origin ?? "reikšmė")} ${sizing.verb} ${issue.maximum.toString()} ${sizing.unit ?? "elementų"}`; - const adj = issue.inclusive ? "ne didesnis kaip" : "mažesnis kaip"; - return `${capitalizeFirstCharacter(origin ?? issue.origin ?? "reikšmė")} turi būti ${adj} ${issue.maximum.toString()} ${sizing?.unit}`; - } - case "too_small": { - const origin = parsedTypeFromType(issue.origin); - const sizing = getSizing(issue.origin, getUnitTypeFromNumber(Number(issue.minimum)), issue.inclusive ?? false, "bigger"); - if (sizing?.verb) - return `${capitalizeFirstCharacter(origin ?? issue.origin ?? "reikšmė")} ${sizing.verb} ${issue.minimum.toString()} ${sizing.unit ?? "elementų"}`; - const adj = issue.inclusive ? "ne mažesnis kaip" : "didesnis kaip"; - return `${capitalizeFirstCharacter(origin ?? issue.origin ?? "reikšmė")} turi būti ${adj} ${issue.minimum.toString()} ${sizing?.unit}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Eilutė privalo prasidėti "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `Eilutė privalo pasibaigti "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Eilutė privalo įtraukti "${_issue.includes}"`; - if (_issue.format === "regex") - return `Eilutė privalo atitikti ${_issue.pattern}`; - return `Neteisingas ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Skaičius privalo būti ${issue.divisor} kartotinis.`; - case "unrecognized_keys": - return `Neatpažint${issue.keys.length > 1 ? "i" : "as"} rakt${issue.keys.length > 1 ? "ai" : "as"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return "Rastas klaidingas raktas"; - case "invalid_union": - return "Klaidinga įvestis"; - case "invalid_element": { - const origin = parsedTypeFromType(issue.origin); - return `${capitalizeFirstCharacter(origin ?? issue.origin ?? "reikšmė")} turi klaidingą įvestį`; - } - default: - return "Klaidinga įvestis"; - } - }; -}; -/* harmony default export */ function lt() { - return { - localeError: lt_error(), - }; +function _isoDate(Class, params) { + return new Class({ + type: "string", + format: "date", + check: "string_format", + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/mk.js - -const mk_error = () => { - const Sizable = { - string: { unit: "знаци", verb: "да имаат" }, - file: { unit: "бајти", verb: "да имаат" }, - array: { unit: "ставки", verb: "да имаат" }, - set: { unit: "ставки", verb: "да имаат" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "број"; - } - case "object": { - if (Array.isArray(data)) { - return "низа"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "внес", - email: "адреса на е-пошта", - url: "URL", - emoji: "емоџи", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO датум и време", - date: "ISO датум", - time: "ISO време", - duration: "ISO времетраење", - ipv4: "IPv4 адреса", - ipv6: "IPv6 адреса", - cidrv4: "IPv4 опсег", - cidrv6: "IPv6 опсег", - base64: "base64-енкодирана низа", - base64url: "base64url-енкодирана низа", - json_string: "JSON низа", - e164: "E.164 број", - jwt: "JWT", - template_literal: "внес", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Грешен внес: се очекува ${issue.expected}, примено ${parsedType(issue.input)}`; - // return `Invalid input: expected ${issue.expected}, received ${util.getParsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Invalid input: expected ${stringifyPrimitive(issue.values[0])}`; - return `Грешана опција: се очекува една ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Премногу голем: се очекува ${issue.origin ?? "вредноста"} да има ${adj}${issue.maximum.toString()} ${sizing.unit ?? "елементи"}`; - return `Премногу голем: се очекува ${issue.origin ?? "вредноста"} да биде ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Премногу мал: се очекува ${issue.origin} да има ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Премногу мал: се очекува ${issue.origin} да биде ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Неважечка низа: мора да започнува со "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `Неважечка низа: мора да завршува со "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Неважечка низа: мора да вклучува "${_issue.includes}"`; - if (_issue.format === "regex") - return `Неважечка низа: мора да одгоара на патернот ${_issue.pattern}`; - return `Invalid ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Грешен број: мора да биде делив со ${issue.divisor}`; - case "unrecognized_keys": - return `${issue.keys.length > 1 ? "Непрепознаени клучеви" : "Непрепознаен клуч"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Грешен клуч во ${issue.origin}`; - case "invalid_union": - return "Грешен внес"; - case "invalid_element": - return `Грешна вредност во ${issue.origin}`; - default: - return `Грешен внес`; - } - }; -}; -/* harmony default export */ function mk() { - return { - localeError: mk_error(), - }; +function _isoTime(Class, params) { + return new Class({ + type: "string", + format: "time", + check: "string_format", + precision: null, + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ms.js - -const ms_error = () => { - const Sizable = { - string: { unit: "aksara", verb: "mempunyai" }, - file: { unit: "bait", verb: "mempunyai" }, - array: { unit: "elemen", verb: "mempunyai" }, - set: { unit: "elemen", verb: "mempunyai" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "nombor"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "input", - email: "alamat e-mel", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "tarikh masa ISO", - date: "tarikh ISO", - time: "masa ISO", - duration: "tempoh ISO", - ipv4: "alamat IPv4", - ipv6: "alamat IPv6", - cidrv4: "julat IPv4", - cidrv6: "julat IPv6", - base64: "string dikodkan base64", - base64url: "string dikodkan base64url", - json_string: "string JSON", - e164: "nombor E.164", - jwt: "JWT", - template_literal: "input", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Input tidak sah: dijangka ${issue.expected}, diterima ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Input tidak sah: dijangka ${stringifyPrimitive(issue.values[0])}`; - return `Pilihan tidak sah: dijangka salah satu daripada ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Terlalu besar: dijangka ${issue.origin ?? "nilai"} ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elemen"}`; - return `Terlalu besar: dijangka ${issue.origin ?? "nilai"} adalah ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Terlalu kecil: dijangka ${issue.origin} ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Terlalu kecil: dijangka ${issue.origin} adalah ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `String tidak sah: mesti bermula dengan "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `String tidak sah: mesti berakhir dengan "${_issue.suffix}"`; - if (_issue.format === "includes") - return `String tidak sah: mesti mengandungi "${_issue.includes}"`; - if (_issue.format === "regex") - return `String tidak sah: mesti sepadan dengan corak ${_issue.pattern}`; - return `${Nouns[_issue.format] ?? issue.format} tidak sah`; - } - case "not_multiple_of": - return `Nombor tidak sah: perlu gandaan ${issue.divisor}`; - case "unrecognized_keys": - return `Kunci tidak dikenali: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Kunci tidak sah dalam ${issue.origin}`; - case "invalid_union": - return "Input tidak sah"; - case "invalid_element": - return `Nilai tidak sah dalam ${issue.origin}`; - default: - return `Input tidak sah`; - } - }; -}; -/* harmony default export */ function ms() { - return { - localeError: ms_error(), - }; +function _isoDuration(Class, params) { + return new Class({ + type: "string", + format: "duration", + check: "string_format", + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/nl.js - -const nl_error = () => { - const Sizable = { - string: { unit: "tekens", verb: "te hebben" }, - file: { unit: "bytes", verb: "te hebben" }, - array: { unit: "elementen", verb: "te hebben" }, - set: { unit: "elementen", verb: "te hebben" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "getal"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "invoer", - email: "emailadres", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO datum en tijd", - date: "ISO datum", - time: "ISO tijd", - duration: "ISO duur", - ipv4: "IPv4-adres", - ipv6: "IPv6-adres", - cidrv4: "IPv4-bereik", - cidrv6: "IPv6-bereik", - base64: "base64-gecodeerde tekst", - base64url: "base64 URL-gecodeerde tekst", - json_string: "JSON string", - e164: "E.164-nummer", - jwt: "JWT", - template_literal: "invoer", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Ongeldige invoer: verwacht ${issue.expected}, ontving ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Ongeldige invoer: verwacht ${stringifyPrimitive(issue.values[0])}`; - return `Ongeldige optie: verwacht één van ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Te groot: verwacht dat ${issue.origin ?? "waarde"} ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementen"}`; - return `Te groot: verwacht dat ${issue.origin ?? "waarde"} ${adj}${issue.maximum.toString()} is`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Te klein: verwacht dat ${issue.origin} ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Te klein: verwacht dat ${issue.origin} ${adj}${issue.minimum.toString()} is`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Ongeldige tekst: moet met "${_issue.prefix}" beginnen`; - } - if (_issue.format === "ends_with") - return `Ongeldige tekst: moet op "${_issue.suffix}" eindigen`; - if (_issue.format === "includes") - return `Ongeldige tekst: moet "${_issue.includes}" bevatten`; - if (_issue.format === "regex") - return `Ongeldige tekst: moet overeenkomen met patroon ${_issue.pattern}`; - return `Ongeldig: ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Ongeldig getal: moet een veelvoud van ${issue.divisor} zijn`; - case "unrecognized_keys": - return `Onbekende key${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Ongeldige key in ${issue.origin}`; - case "invalid_union": - return "Ongeldige invoer"; - case "invalid_element": - return `Ongeldige waarde in ${issue.origin}`; - default: - return `Ongeldige invoer`; - } - }; -}; -/* harmony default export */ function nl() { - return { - localeError: nl_error(), - }; +function _number(Class, params) { + return new Class({ + type: "number", + checks: [], + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/no.js - -const no_error = () => { - const Sizable = { - string: { unit: "tegn", verb: "å ha" }, - file: { unit: "bytes", verb: "å ha" }, - array: { unit: "elementer", verb: "å inneholde" }, - set: { unit: "elementer", verb: "å inneholde" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "tall"; - } - case "object": { - if (Array.isArray(data)) { - return "liste"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "input", - email: "e-postadresse", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO dato- og klokkeslett", - date: "ISO-dato", - time: "ISO-klokkeslett", - duration: "ISO-varighet", - ipv4: "IPv4-område", - ipv6: "IPv6-område", - cidrv4: "IPv4-spekter", - cidrv6: "IPv6-spekter", - base64: "base64-enkodet streng", - base64url: "base64url-enkodet streng", - json_string: "JSON-streng", - e164: "E.164-nummer", - jwt: "JWT", - template_literal: "input", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Ugyldig input: forventet ${issue.expected}, fikk ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Ugyldig verdi: forventet ${stringifyPrimitive(issue.values[0])}`; - return `Ugyldig valg: forventet en av ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `For stor(t): forventet ${issue.origin ?? "value"} til å ha ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementer"}`; - return `For stor(t): forventet ${issue.origin ?? "value"} til å ha ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `For lite(n): forventet ${issue.origin} til å ha ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `For lite(n): forventet ${issue.origin} til å ha ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Ugyldig streng: må starte med "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Ugyldig streng: må ende med "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Ugyldig streng: må inneholde "${_issue.includes}"`; - if (_issue.format === "regex") - return `Ugyldig streng: må matche mønsteret ${_issue.pattern}`; - return `Ugyldig ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Ugyldig tall: må være et multiplum av ${issue.divisor}`; - case "unrecognized_keys": - return `${issue.keys.length > 1 ? "Ukjente nøkler" : "Ukjent nøkkel"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Ugyldig nøkkel i ${issue.origin}`; - case "invalid_union": - return "Ugyldig input"; - case "invalid_element": - return `Ugyldig verdi i ${issue.origin}`; - default: - return `Ugyldig input`; - } - }; -}; -/* harmony default export */ function no() { - return { - localeError: no_error(), - }; +function _coercedNumber(Class, params) { + return new Class({ + type: "number", + coerce: true, + checks: [], + ...util.normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ota.js - -const ota_error = () => { - const Sizable = { - string: { unit: "harf", verb: "olmalıdır" }, - file: { unit: "bayt", verb: "olmalıdır" }, - array: { unit: "unsur", verb: "olmalıdır" }, - set: { unit: "unsur", verb: "olmalıdır" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "numara"; - } - case "object": { - if (Array.isArray(data)) { - return "saf"; - } - if (data === null) { - return "gayb"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "giren", - email: "epostagâh", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO hengâmı", - date: "ISO tarihi", - time: "ISO zamanı", - duration: "ISO müddeti", - ipv4: "IPv4 nişânı", - ipv6: "IPv6 nişânı", - cidrv4: "IPv4 menzili", - cidrv6: "IPv6 menzili", - base64: "base64-şifreli metin", - base64url: "base64url-şifreli metin", - json_string: "JSON metin", - e164: "E.164 sayısı", - jwt: "JWT", - template_literal: "giren", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Fâsit giren: umulan ${issue.expected}, alınan ${parsedType(issue.input)}`; - // return `Fâsit giren: umulan ${issue.expected}, alınan ${util.getParsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Fâsit giren: umulan ${stringifyPrimitive(issue.values[0])}`; - return `Fâsit tercih: mûteberler ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Fazla büyük: ${issue.origin ?? "value"}, ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elements"} sahip olmalıydı.`; - return `Fazla büyük: ${issue.origin ?? "value"}, ${adj}${issue.maximum.toString()} olmalıydı.`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Fazla küçük: ${issue.origin}, ${adj}${issue.minimum.toString()} ${sizing.unit} sahip olmalıydı.`; - } - return `Fazla küçük: ${issue.origin}, ${adj}${issue.minimum.toString()} olmalıydı.`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Fâsit metin: "${_issue.prefix}" ile başlamalı.`; - if (_issue.format === "ends_with") - return `Fâsit metin: "${_issue.suffix}" ile bitmeli.`; - if (_issue.format === "includes") - return `Fâsit metin: "${_issue.includes}" ihtivâ etmeli.`; - if (_issue.format === "regex") - return `Fâsit metin: ${_issue.pattern} nakşına uymalı.`; - return `Fâsit ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Fâsit sayı: ${issue.divisor} katı olmalıydı.`; - case "unrecognized_keys": - return `Tanınmayan anahtar ${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `${issue.origin} için tanınmayan anahtar var.`; - case "invalid_union": - return "Giren tanınamadı."; - case "invalid_element": - return `${issue.origin} için tanınmayan kıymet var.`; - default: - return `Kıymet tanınamadı.`; - } - }; -}; -/* harmony default export */ function ota() { - return { - localeError: ota_error(), - }; +function _int(Class, params) { + return new Class({ + type: "number", + check: "number_format", + abort: false, + format: "safeint", + ...normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ps.js - -const ps_error = () => { - const Sizable = { - string: { unit: "توکي", verb: "ولري" }, - file: { unit: "بایټس", verb: "ولري" }, - array: { unit: "توکي", verb: "ولري" }, - set: { unit: "توکي", verb: "ولري" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "عدد"; - } - case "object": { - if (Array.isArray(data)) { - return "ارې"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "ورودي", - email: "بریښنالیک", - url: "یو آر ال", - emoji: "ایموجي", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "نیټه او وخت", - date: "نېټه", - time: "وخت", - duration: "موده", - ipv4: "د IPv4 پته", - ipv6: "د IPv6 پته", - cidrv4: "د IPv4 ساحه", - cidrv6: "د IPv6 ساحه", - base64: "base64-encoded متن", - base64url: "base64url-encoded متن", - json_string: "JSON متن", - e164: "د E.164 شمېره", - jwt: "JWT", - template_literal: "ورودي", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `ناسم ورودي: باید ${issue.expected} وای, مګر ${parsedType(issue.input)} ترلاسه شو`; - case "invalid_value": - if (issue.values.length === 1) { - return `ناسم ورودي: باید ${stringifyPrimitive(issue.values[0])} وای`; - } - return `ناسم انتخاب: باید یو له ${joinValues(issue.values, "|")} څخه وای`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `ډیر لوی: ${issue.origin ?? "ارزښت"} باید ${adj}${issue.maximum.toString()} ${sizing.unit ?? "عنصرونه"} ولري`; - } - return `ډیر لوی: ${issue.origin ?? "ارزښت"} باید ${adj}${issue.maximum.toString()} وي`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `ډیر کوچنی: ${issue.origin} باید ${adj}${issue.minimum.toString()} ${sizing.unit} ولري`; - } - return `ډیر کوچنی: ${issue.origin} باید ${adj}${issue.minimum.toString()} وي`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `ناسم متن: باید د "${_issue.prefix}" سره پیل شي`; - } - if (_issue.format === "ends_with") { - return `ناسم متن: باید د "${_issue.suffix}" سره پای ته ورسيږي`; - } - if (_issue.format === "includes") { - return `ناسم متن: باید "${_issue.includes}" ولري`; - } - if (_issue.format === "regex") { - return `ناسم متن: باید د ${_issue.pattern} سره مطابقت ولري`; - } - return `${Nouns[_issue.format] ?? issue.format} ناسم دی`; - } - case "not_multiple_of": - return `ناسم عدد: باید د ${issue.divisor} مضرب وي`; - case "unrecognized_keys": - return `ناسم ${issue.keys.length > 1 ? "کلیډونه" : "کلیډ"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `ناسم کلیډ په ${issue.origin} کې`; - case "invalid_union": - return `ناسمه ورودي`; - case "invalid_element": - return `ناسم عنصر په ${issue.origin} کې`; - default: - return `ناسمه ورودي`; - } - }; -}; -/* harmony default export */ function ps() { - return { - localeError: ps_error(), - }; +function _float32(Class, params) { + return new Class({ + type: "number", + check: "number_format", + abort: false, + format: "float32", + ...util.normalizeParams(params), + }); } - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/pl.js - -const pl_error = () => { - const Sizable = { - string: { unit: "znaków", verb: "mieć" }, - file: { unit: "bajtów", verb: "mieć" }, - array: { unit: "elementów", verb: "mieć" }, - set: { unit: "elementów", verb: "mieć" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "liczba"; - } - case "object": { - if (Array.isArray(data)) { - return "tablica"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "wyrażenie", - email: "adres email", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "data i godzina w formacie ISO", - date: "data w formacie ISO", - time: "godzina w formacie ISO", - duration: "czas trwania ISO", - ipv4: "adres IPv4", - ipv6: "adres IPv6", - cidrv4: "zakres IPv4", - cidrv6: "zakres IPv6", - base64: "ciąg znaków zakodowany w formacie base64", - base64url: "ciąg znaków zakodowany w formacie base64url", - json_string: "ciąg znaków w formacie JSON", - e164: "liczba E.164", - jwt: "JWT", - template_literal: "wejście", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Nieprawidłowe dane wejściowe: oczekiwano ${issue.expected}, otrzymano ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Nieprawidłowe dane wejściowe: oczekiwano ${stringifyPrimitive(issue.values[0])}`; - return `Nieprawidłowa opcja: oczekiwano jednej z wartości ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Za duża wartość: oczekiwano, że ${issue.origin ?? "wartość"} będzie mieć ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementów"}`; - } - return `Zbyt duż(y/a/e): oczekiwano, że ${issue.origin ?? "wartość"} będzie wynosić ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Za mała wartość: oczekiwano, że ${issue.origin ?? "wartość"} będzie mieć ${adj}${issue.minimum.toString()} ${sizing.unit ?? "elementów"}`; - } - return `Zbyt mał(y/a/e): oczekiwano, że ${issue.origin ?? "wartość"} będzie wynosić ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Nieprawidłowy ciąg znaków: musi zaczynać się od "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Nieprawidłowy ciąg znaków: musi kończyć się na "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Nieprawidłowy ciąg znaków: musi zawierać "${_issue.includes}"`; - if (_issue.format === "regex") - return `Nieprawidłowy ciąg znaków: musi odpowiadać wzorcowi ${_issue.pattern}`; - return `Nieprawidłow(y/a/e) ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Nieprawidłowa liczba: musi być wielokrotnością ${issue.divisor}`; - case "unrecognized_keys": - return `Nierozpoznane klucze${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Nieprawidłowy klucz w ${issue.origin}`; - case "invalid_union": - return "Nieprawidłowe dane wejściowe"; - case "invalid_element": - return `Nieprawidłowa wartość w ${issue.origin}`; - default: - return `Nieprawidłowe dane wejściowe`; - } - }; -}; -/* harmony default export */ function pl() { - return { - localeError: pl_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/pt.js - -const pt_error = () => { - const Sizable = { - string: { unit: "caracteres", verb: "ter" }, - file: { unit: "bytes", verb: "ter" }, - array: { unit: "itens", verb: "ter" }, - set: { unit: "itens", verb: "ter" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "número"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "nulo"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "padrão", - email: "endereço de e-mail", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "data e hora ISO", - date: "data ISO", - time: "hora ISO", - duration: "duração ISO", - ipv4: "endereço IPv4", - ipv6: "endereço IPv6", - cidrv4: "faixa de IPv4", - cidrv6: "faixa de IPv6", - base64: "texto codificado em base64", - base64url: "URL codificada em base64", - json_string: "texto JSON", - e164: "número E.164", - jwt: "JWT", - template_literal: "entrada", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Tipo inválido: esperado ${issue.expected}, recebido ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Entrada inválida: esperado ${stringifyPrimitive(issue.values[0])}`; - return `Opção inválida: esperada uma das ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Muito grande: esperado que ${issue.origin ?? "valor"} tivesse ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementos"}`; - return `Muito grande: esperado que ${issue.origin ?? "valor"} fosse ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Muito pequeno: esperado que ${issue.origin} tivesse ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Muito pequeno: esperado que ${issue.origin} fosse ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Texto inválido: deve começar com "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Texto inválido: deve terminar com "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Texto inválido: deve incluir "${_issue.includes}"`; - if (_issue.format === "regex") - return `Texto inválido: deve corresponder ao padrão ${_issue.pattern}`; - return `${Nouns[_issue.format] ?? issue.format} inválido`; - } - case "not_multiple_of": - return `Número inválido: deve ser múltiplo de ${issue.divisor}`; - case "unrecognized_keys": - return `Chave${issue.keys.length > 1 ? "s" : ""} desconhecida${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Chave inválida em ${issue.origin}`; - case "invalid_union": - return "Entrada inválida"; - case "invalid_element": - return `Valor inválido em ${issue.origin}`; - default: - return `Campo inválido`; - } - }; -}; -/* harmony default export */ function pt() { - return { - localeError: pt_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ru.js - -function getRussianPlural(count, one, few, many) { - const absCount = Math.abs(count); - const lastDigit = absCount % 10; - const lastTwoDigits = absCount % 100; - if (lastTwoDigits >= 11 && lastTwoDigits <= 19) { - return many; - } - if (lastDigit === 1) { - return one; - } - if (lastDigit >= 2 && lastDigit <= 4) { - return few; - } - return many; -} -const ru_error = () => { - const Sizable = { - string: { - unit: { - one: "символ", - few: "символа", - many: "символов", - }, - verb: "иметь", - }, - file: { - unit: { - one: "байт", - few: "байта", - many: "байт", - }, - verb: "иметь", - }, - array: { - unit: { - one: "элемент", - few: "элемента", - many: "элементов", - }, - verb: "иметь", - }, - set: { - unit: { - one: "элемент", - few: "элемента", - many: "элементов", - }, - verb: "иметь", - }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "число"; - } - case "object": { - if (Array.isArray(data)) { - return "массив"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "ввод", - email: "email адрес", - url: "URL", - emoji: "эмодзи", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO дата и время", - date: "ISO дата", - time: "ISO время", - duration: "ISO длительность", - ipv4: "IPv4 адрес", - ipv6: "IPv6 адрес", - cidrv4: "IPv4 диапазон", - cidrv6: "IPv6 диапазон", - base64: "строка в формате base64", - base64url: "строка в формате base64url", - json_string: "JSON строка", - e164: "номер E.164", - jwt: "JWT", - template_literal: "ввод", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Неверный ввод: ожидалось ${issue.expected}, получено ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Неверный ввод: ожидалось ${stringifyPrimitive(issue.values[0])}`; - return `Неверный вариант: ожидалось одно из ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) { - const maxValue = Number(issue.maximum); - const unit = getRussianPlural(maxValue, sizing.unit.one, sizing.unit.few, sizing.unit.many); - return `Слишком большое значение: ожидалось, что ${issue.origin ?? "значение"} будет иметь ${adj}${issue.maximum.toString()} ${unit}`; - } - return `Слишком большое значение: ожидалось, что ${issue.origin ?? "значение"} будет ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - const minValue = Number(issue.minimum); - const unit = getRussianPlural(minValue, sizing.unit.one, sizing.unit.few, sizing.unit.many); - return `Слишком маленькое значение: ожидалось, что ${issue.origin} будет иметь ${adj}${issue.minimum.toString()} ${unit}`; - } - return `Слишком маленькое значение: ожидалось, что ${issue.origin} будет ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Неверная строка: должна начинаться с "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Неверная строка: должна заканчиваться на "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Неверная строка: должна содержать "${_issue.includes}"`; - if (_issue.format === "regex") - return `Неверная строка: должна соответствовать шаблону ${_issue.pattern}`; - return `Неверный ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Неверное число: должно быть кратным ${issue.divisor}`; - case "unrecognized_keys": - return `Нераспознанн${issue.keys.length > 1 ? "ые" : "ый"} ключ${issue.keys.length > 1 ? "и" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Неверный ключ в ${issue.origin}`; - case "invalid_union": - return "Неверные входные данные"; - case "invalid_element": - return `Неверное значение в ${issue.origin}`; - default: - return `Неверные входные данные`; - } - }; -}; -/* harmony default export */ function ru() { - return { - localeError: ru_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/sl.js - -const sl_error = () => { - const Sizable = { - string: { unit: "znakov", verb: "imeti" }, - file: { unit: "bajtov", verb: "imeti" }, - array: { unit: "elementov", verb: "imeti" }, - set: { unit: "elementov", verb: "imeti" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "število"; - } - case "object": { - if (Array.isArray(data)) { - return "tabela"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "vnos", - email: "e-poštni naslov", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO datum in čas", - date: "ISO datum", - time: "ISO čas", - duration: "ISO trajanje", - ipv4: "IPv4 naslov", - ipv6: "IPv6 naslov", - cidrv4: "obseg IPv4", - cidrv6: "obseg IPv6", - base64: "base64 kodiran niz", - base64url: "base64url kodiran niz", - json_string: "JSON niz", - e164: "E.164 številka", - jwt: "JWT", - template_literal: "vnos", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Neveljaven vnos: pričakovano ${issue.expected}, prejeto ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Neveljaven vnos: pričakovano ${stringifyPrimitive(issue.values[0])}`; - return `Neveljavna možnost: pričakovano eno izmed ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Preveliko: pričakovano, da bo ${issue.origin ?? "vrednost"} imelo ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementov"}`; - return `Preveliko: pričakovano, da bo ${issue.origin ?? "vrednost"} ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Premajhno: pričakovano, da bo ${issue.origin} imelo ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Premajhno: pričakovano, da bo ${issue.origin} ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Neveljaven niz: mora se začeti z "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `Neveljaven niz: mora se končati z "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Neveljaven niz: mora vsebovati "${_issue.includes}"`; - if (_issue.format === "regex") - return `Neveljaven niz: mora ustrezati vzorcu ${_issue.pattern}`; - return `Neveljaven ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Neveljavno število: mora biti večkratnik ${issue.divisor}`; - case "unrecognized_keys": - return `Neprepoznan${issue.keys.length > 1 ? "i ključi" : " ključ"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Neveljaven ključ v ${issue.origin}`; - case "invalid_union": - return "Neveljaven vnos"; - case "invalid_element": - return `Neveljavna vrednost v ${issue.origin}`; - default: - return "Neveljaven vnos"; - } - }; -}; -/* harmony default export */ function sl() { - return { - localeError: sl_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/sv.js - -const sv_error = () => { - const Sizable = { - string: { unit: "tecken", verb: "att ha" }, - file: { unit: "bytes", verb: "att ha" }, - array: { unit: "objekt", verb: "att innehålla" }, - set: { unit: "objekt", verb: "att innehålla" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "antal"; - } - case "object": { - if (Array.isArray(data)) { - return "lista"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "reguljärt uttryck", - email: "e-postadress", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO-datum och tid", - date: "ISO-datum", - time: "ISO-tid", - duration: "ISO-varaktighet", - ipv4: "IPv4-intervall", - ipv6: "IPv6-intervall", - cidrv4: "IPv4-spektrum", - cidrv6: "IPv6-spektrum", - base64: "base64-kodad sträng", - base64url: "base64url-kodad sträng", - json_string: "JSON-sträng", - e164: "E.164-nummer", - jwt: "JWT", - template_literal: "mall-literal", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Ogiltig inmatning: förväntat ${issue.expected}, fick ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Ogiltig inmatning: förväntat ${stringifyPrimitive(issue.values[0])}`; - return `Ogiltigt val: förväntade en av ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `För stor(t): förväntade ${issue.origin ?? "värdet"} att ha ${adj}${issue.maximum.toString()} ${sizing.unit ?? "element"}`; - } - return `För stor(t): förväntat ${issue.origin ?? "värdet"} att ha ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `För lite(t): förväntade ${issue.origin ?? "värdet"} att ha ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `För lite(t): förväntade ${issue.origin ?? "värdet"} att ha ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `Ogiltig sträng: måste börja med "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `Ogiltig sträng: måste sluta med "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Ogiltig sträng: måste innehålla "${_issue.includes}"`; - if (_issue.format === "regex") - return `Ogiltig sträng: måste matcha mönstret "${_issue.pattern}"`; - return `Ogiltig(t) ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Ogiltigt tal: måste vara en multipel av ${issue.divisor}`; - case "unrecognized_keys": - return `${issue.keys.length > 1 ? "Okända nycklar" : "Okänd nyckel"}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Ogiltig nyckel i ${issue.origin ?? "värdet"}`; - case "invalid_union": - return "Ogiltig input"; - case "invalid_element": - return `Ogiltigt värde i ${issue.origin ?? "värdet"}`; - default: - return `Ogiltig input`; - } - }; -}; -/* harmony default export */ function sv() { - return { - localeError: sv_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ta.js - -const ta_error = () => { - const Sizable = { - string: { unit: "எழுத்துக்கள்", verb: "கொண்டிருக்க வேண்டும்" }, - file: { unit: "பைட்டுகள்", verb: "கொண்டிருக்க வேண்டும்" }, - array: { unit: "உறுப்புகள்", verb: "கொண்டிருக்க வேண்டும்" }, - set: { unit: "உறுப்புகள்", verb: "கொண்டிருக்க வேண்டும்" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "எண் அல்லாதது" : "எண்"; - } - case "object": { - if (Array.isArray(data)) { - return "அணி"; - } - if (data === null) { - return "வெறுமை"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "உள்ளீடு", - email: "மின்னஞ்சல் முகவரி", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO தேதி நேரம்", - date: "ISO தேதி", - time: "ISO நேரம்", - duration: "ISO கால அளவு", - ipv4: "IPv4 முகவரி", - ipv6: "IPv6 முகவரி", - cidrv4: "IPv4 வரம்பு", - cidrv6: "IPv6 வரம்பு", - base64: "base64-encoded சரம்", - base64url: "base64url-encoded சரம்", - json_string: "JSON சரம்", - e164: "E.164 எண்", - jwt: "JWT", - template_literal: "input", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `தவறான உள்ளீடு: எதிர்பார்க்கப்பட்டது ${issue.expected}, பெறப்பட்டது ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `தவறான உள்ளீடு: எதிர்பார்க்கப்பட்டது ${stringifyPrimitive(issue.values[0])}`; - return `தவறான விருப்பம்: எதிர்பார்க்கப்பட்டது ${joinValues(issue.values, "|")} இல் ஒன்று`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `மிக பெரியது: எதிர்பார்க்கப்பட்டது ${issue.origin ?? "மதிப்பு"} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "உறுப்புகள்"} ஆக இருக்க வேண்டும்`; - } - return `மிக பெரியது: எதிர்பார்க்கப்பட்டது ${issue.origin ?? "மதிப்பு"} ${adj}${issue.maximum.toString()} ஆக இருக்க வேண்டும்`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `மிகச் சிறியது: எதிர்பார்க்கப்பட்டது ${issue.origin} ${adj}${issue.minimum.toString()} ${sizing.unit} ஆக இருக்க வேண்டும்`; // - } - return `மிகச் சிறியது: எதிர்பார்க்கப்பட்டது ${issue.origin} ${adj}${issue.minimum.toString()} ஆக இருக்க வேண்டும்`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `தவறான சரம்: "${_issue.prefix}" இல் தொடங்க வேண்டும்`; - if (_issue.format === "ends_with") - return `தவறான சரம்: "${_issue.suffix}" இல் முடிவடைய வேண்டும்`; - if (_issue.format === "includes") - return `தவறான சரம்: "${_issue.includes}" ஐ உள்ளடக்க வேண்டும்`; - if (_issue.format === "regex") - return `தவறான சரம்: ${_issue.pattern} முறைபாட்டுடன் பொருந்த வேண்டும்`; - return `தவறான ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `தவறான எண்: ${issue.divisor} இன் பலமாக இருக்க வேண்டும்`; - case "unrecognized_keys": - return `அடையாளம் தெரியாத விசை${issue.keys.length > 1 ? "கள்" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `${issue.origin} இல் தவறான விசை`; - case "invalid_union": - return "தவறான உள்ளீடு"; - case "invalid_element": - return `${issue.origin} இல் தவறான மதிப்பு`; - default: - return `தவறான உள்ளீடு`; - } - }; -}; -/* harmony default export */ function ta() { - return { - localeError: ta_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/th.js - -const th_error = () => { - const Sizable = { - string: { unit: "ตัวอักษร", verb: "ควรมี" }, - file: { unit: "ไบต์", verb: "ควรมี" }, - array: { unit: "รายการ", verb: "ควรมี" }, - set: { unit: "รายการ", verb: "ควรมี" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "ไม่ใช่ตัวเลข (NaN)" : "ตัวเลข"; - } - case "object": { - if (Array.isArray(data)) { - return "อาร์เรย์ (Array)"; - } - if (data === null) { - return "ไม่มีค่า (null)"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "ข้อมูลที่ป้อน", - email: "ที่อยู่อีเมล", - url: "URL", - emoji: "อิโมจิ", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "วันที่เวลาแบบ ISO", - date: "วันที่แบบ ISO", - time: "เวลาแบบ ISO", - duration: "ช่วงเวลาแบบ ISO", - ipv4: "ที่อยู่ IPv4", - ipv6: "ที่อยู่ IPv6", - cidrv4: "ช่วง IP แบบ IPv4", - cidrv6: "ช่วง IP แบบ IPv6", - base64: "ข้อความแบบ Base64", - base64url: "ข้อความแบบ Base64 สำหรับ URL", - json_string: "ข้อความแบบ JSON", - e164: "เบอร์โทรศัพท์ระหว่างประเทศ (E.164)", - jwt: "โทเคน JWT", - template_literal: "ข้อมูลที่ป้อน", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `ประเภทข้อมูลไม่ถูกต้อง: ควรเป็น ${issue.expected} แต่ได้รับ ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `ค่าไม่ถูกต้อง: ควรเป็น ${stringifyPrimitive(issue.values[0])}`; - return `ตัวเลือกไม่ถูกต้อง: ควรเป็นหนึ่งใน ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "ไม่เกิน" : "น้อยกว่า"; - const sizing = getSizing(issue.origin); - if (sizing) - return `เกินกำหนด: ${issue.origin ?? "ค่า"} ควรมี${adj} ${issue.maximum.toString()} ${sizing.unit ?? "รายการ"}`; - return `เกินกำหนด: ${issue.origin ?? "ค่า"} ควรมี${adj} ${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? "อย่างน้อย" : "มากกว่า"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `น้อยกว่ากำหนด: ${issue.origin} ควรมี${adj} ${issue.minimum.toString()} ${sizing.unit}`; - } - return `น้อยกว่ากำหนด: ${issue.origin} ควรมี${adj} ${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `รูปแบบไม่ถูกต้อง: ข้อความต้องขึ้นต้นด้วย "${_issue.prefix}"`; - } - if (_issue.format === "ends_with") - return `รูปแบบไม่ถูกต้อง: ข้อความต้องลงท้ายด้วย "${_issue.suffix}"`; - if (_issue.format === "includes") - return `รูปแบบไม่ถูกต้อง: ข้อความต้องมี "${_issue.includes}" อยู่ในข้อความ`; - if (_issue.format === "regex") - return `รูปแบบไม่ถูกต้อง: ต้องตรงกับรูปแบบที่กำหนด ${_issue.pattern}`; - return `รูปแบบไม่ถูกต้อง: ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `ตัวเลขไม่ถูกต้อง: ต้องเป็นจำนวนที่หารด้วย ${issue.divisor} ได้ลงตัว`; - case "unrecognized_keys": - return `พบคีย์ที่ไม่รู้จัก: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `คีย์ไม่ถูกต้องใน ${issue.origin}`; - case "invalid_union": - return "ข้อมูลไม่ถูกต้อง: ไม่ตรงกับรูปแบบยูเนียนที่กำหนดไว้"; - case "invalid_element": - return `ข้อมูลไม่ถูกต้องใน ${issue.origin}`; - default: - return `ข้อมูลไม่ถูกต้อง`; - } - }; -}; -/* harmony default export */ function th() { - return { - localeError: th_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/tr.js - -const tr_parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; -}; -const tr_error = () => { - const Sizable = { - string: { unit: "karakter", verb: "olmalı" }, - file: { unit: "bayt", verb: "olmalı" }, - array: { unit: "öğe", verb: "olmalı" }, - set: { unit: "öğe", verb: "olmalı" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const Nouns = { - regex: "girdi", - email: "e-posta adresi", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO tarih ve saat", - date: "ISO tarih", - time: "ISO saat", - duration: "ISO süre", - ipv4: "IPv4 adresi", - ipv6: "IPv6 adresi", - cidrv4: "IPv4 aralığı", - cidrv6: "IPv6 aralığı", - base64: "base64 ile şifrelenmiş metin", - base64url: "base64url ile şifrelenmiş metin", - json_string: "JSON dizesi", - e164: "E.164 sayısı", - jwt: "JWT", - template_literal: "Şablon dizesi", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Geçersiz değer: beklenen ${issue.expected}, alınan ${tr_parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Geçersiz değer: beklenen ${stringifyPrimitive(issue.values[0])}`; - return `Geçersiz seçenek: aşağıdakilerden biri olmalı: ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Çok büyük: beklenen ${issue.origin ?? "değer"} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "öğe"}`; - return `Çok büyük: beklenen ${issue.origin ?? "değer"} ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Çok küçük: beklenen ${issue.origin} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - return `Çok küçük: beklenen ${issue.origin} ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Geçersiz metin: "${_issue.prefix}" ile başlamalı`; - if (_issue.format === "ends_with") - return `Geçersiz metin: "${_issue.suffix}" ile bitmeli`; - if (_issue.format === "includes") - return `Geçersiz metin: "${_issue.includes}" içermeli`; - if (_issue.format === "regex") - return `Geçersiz metin: ${_issue.pattern} desenine uymalı`; - return `Geçersiz ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Geçersiz sayı: ${issue.divisor} ile tam bölünebilmeli`; - case "unrecognized_keys": - return `Tanınmayan anahtar${issue.keys.length > 1 ? "lar" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `${issue.origin} içinde geçersiz anahtar`; - case "invalid_union": - return "Geçersiz değer"; - case "invalid_element": - return `${issue.origin} içinde geçersiz değer`; - default: - return `Geçersiz değer`; - } - }; -}; -/* harmony default export */ function tr() { - return { - localeError: tr_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/uk.js - -const uk_error = () => { - const Sizable = { - string: { unit: "символів", verb: "матиме" }, - file: { unit: "байтів", verb: "матиме" }, - array: { unit: "елементів", verb: "матиме" }, - set: { unit: "елементів", verb: "матиме" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "число"; - } - case "object": { - if (Array.isArray(data)) { - return "масив"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "вхідні дані", - email: "адреса електронної пошти", - url: "URL", - emoji: "емодзі", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "дата та час ISO", - date: "дата ISO", - time: "час ISO", - duration: "тривалість ISO", - ipv4: "адреса IPv4", - ipv6: "адреса IPv6", - cidrv4: "діапазон IPv4", - cidrv6: "діапазон IPv6", - base64: "рядок у кодуванні base64", - base64url: "рядок у кодуванні base64url", - json_string: "рядок JSON", - e164: "номер E.164", - jwt: "JWT", - template_literal: "вхідні дані", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Неправильні вхідні дані: очікується ${issue.expected}, отримано ${parsedType(issue.input)}`; - // return `Неправильні вхідні дані: очікується ${issue.expected}, отримано ${util.getParsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Неправильні вхідні дані: очікується ${stringifyPrimitive(issue.values[0])}`; - return `Неправильна опція: очікується одне з ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Занадто велике: очікується, що ${issue.origin ?? "значення"} ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "елементів"}`; - return `Занадто велике: очікується, що ${issue.origin ?? "значення"} буде ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Занадто мале: очікується, що ${issue.origin} ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Занадто мале: очікується, що ${issue.origin} буде ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Неправильний рядок: повинен починатися з "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Неправильний рядок: повинен закінчуватися на "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Неправильний рядок: повинен містити "${_issue.includes}"`; - if (_issue.format === "regex") - return `Неправильний рядок: повинен відповідати шаблону ${_issue.pattern}`; - return `Неправильний ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Неправильне число: повинно бути кратним ${issue.divisor}`; - case "unrecognized_keys": - return `Нерозпізнаний ключ${issue.keys.length > 1 ? "і" : ""}: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Неправильний ключ у ${issue.origin}`; - case "invalid_union": - return "Неправильні вхідні дані"; - case "invalid_element": - return `Неправильне значення у ${issue.origin}`; - default: - return `Неправильні вхідні дані`; - } - }; -}; -/* harmony default export */ function uk() { - return { - localeError: uk_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ua.js - -/** @deprecated Use `uk` instead. */ -/* harmony default export */ function ua() { - return uk(); -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/ur.js - -const ur_error = () => { - const Sizable = { - string: { unit: "حروف", verb: "ہونا" }, - file: { unit: "بائٹس", verb: "ہونا" }, - array: { unit: "آئٹمز", verb: "ہونا" }, - set: { unit: "آئٹمز", verb: "ہونا" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "نمبر"; - } - case "object": { - if (Array.isArray(data)) { - return "آرے"; - } - if (data === null) { - return "نل"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "ان پٹ", - email: "ای میل ایڈریس", - url: "یو آر ایل", - emoji: "ایموجی", - uuid: "یو یو آئی ڈی", - uuidv4: "یو یو آئی ڈی وی 4", - uuidv6: "یو یو آئی ڈی وی 6", - nanoid: "نینو آئی ڈی", - guid: "جی یو آئی ڈی", - cuid: "سی یو آئی ڈی", - cuid2: "سی یو آئی ڈی 2", - ulid: "یو ایل آئی ڈی", - xid: "ایکس آئی ڈی", - ksuid: "کے ایس یو آئی ڈی", - datetime: "آئی ایس او ڈیٹ ٹائم", - date: "آئی ایس او تاریخ", - time: "آئی ایس او وقت", - duration: "آئی ایس او مدت", - ipv4: "آئی پی وی 4 ایڈریس", - ipv6: "آئی پی وی 6 ایڈریس", - cidrv4: "آئی پی وی 4 رینج", - cidrv6: "آئی پی وی 6 رینج", - base64: "بیس 64 ان کوڈڈ سٹرنگ", - base64url: "بیس 64 یو آر ایل ان کوڈڈ سٹرنگ", - json_string: "جے ایس او این سٹرنگ", - e164: "ای 164 نمبر", - jwt: "جے ڈبلیو ٹی", - template_literal: "ان پٹ", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `غلط ان پٹ: ${issue.expected} متوقع تھا، ${parsedType(issue.input)} موصول ہوا`; - case "invalid_value": - if (issue.values.length === 1) - return `غلط ان پٹ: ${stringifyPrimitive(issue.values[0])} متوقع تھا`; - return `غلط آپشن: ${joinValues(issue.values, "|")} میں سے ایک متوقع تھا`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `بہت بڑا: ${issue.origin ?? "ویلیو"} کے ${adj}${issue.maximum.toString()} ${sizing.unit ?? "عناصر"} ہونے متوقع تھے`; - return `بہت بڑا: ${issue.origin ?? "ویلیو"} کا ${adj}${issue.maximum.toString()} ہونا متوقع تھا`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `بہت چھوٹا: ${issue.origin} کے ${adj}${issue.minimum.toString()} ${sizing.unit} ہونے متوقع تھے`; - } - return `بہت چھوٹا: ${issue.origin} کا ${adj}${issue.minimum.toString()} ہونا متوقع تھا`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `غلط سٹرنگ: "${_issue.prefix}" سے شروع ہونا چاہیے`; - } - if (_issue.format === "ends_with") - return `غلط سٹرنگ: "${_issue.suffix}" پر ختم ہونا چاہیے`; - if (_issue.format === "includes") - return `غلط سٹرنگ: "${_issue.includes}" شامل ہونا چاہیے`; - if (_issue.format === "regex") - return `غلط سٹرنگ: پیٹرن ${_issue.pattern} سے میچ ہونا چاہیے`; - return `غلط ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `غلط نمبر: ${issue.divisor} کا مضاعف ہونا چاہیے`; - case "unrecognized_keys": - return `غیر تسلیم شدہ کی${issue.keys.length > 1 ? "ز" : ""}: ${joinValues(issue.keys, "، ")}`; - case "invalid_key": - return `${issue.origin} میں غلط کی`; - case "invalid_union": - return "غلط ان پٹ"; - case "invalid_element": - return `${issue.origin} میں غلط ویلیو`; - default: - return `غلط ان پٹ`; - } - }; -}; -/* harmony default export */ function ur() { - return { - localeError: ur_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/vi.js - -const vi_error = () => { - const Sizable = { - string: { unit: "ký tự", verb: "có" }, - file: { unit: "byte", verb: "có" }, - array: { unit: "phần tử", verb: "có" }, - set: { unit: "phần tử", verb: "có" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "số"; - } - case "object": { - if (Array.isArray(data)) { - return "mảng"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "đầu vào", - email: "địa chỉ email", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ngày giờ ISO", - date: "ngày ISO", - time: "giờ ISO", - duration: "khoảng thời gian ISO", - ipv4: "địa chỉ IPv4", - ipv6: "địa chỉ IPv6", - cidrv4: "dải IPv4", - cidrv6: "dải IPv6", - base64: "chuỗi mã hóa base64", - base64url: "chuỗi mã hóa base64url", - json_string: "chuỗi JSON", - e164: "số E.164", - jwt: "JWT", - template_literal: "đầu vào", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Đầu vào không hợp lệ: mong đợi ${issue.expected}, nhận được ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Đầu vào không hợp lệ: mong đợi ${stringifyPrimitive(issue.values[0])}`; - return `Tùy chọn không hợp lệ: mong đợi một trong các giá trị ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Quá lớn: mong đợi ${issue.origin ?? "giá trị"} ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "phần tử"}`; - return `Quá lớn: mong đợi ${issue.origin ?? "giá trị"} ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `Quá nhỏ: mong đợi ${issue.origin} ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `Quá nhỏ: mong đợi ${issue.origin} ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Chuỗi không hợp lệ: phải bắt đầu bằng "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Chuỗi không hợp lệ: phải kết thúc bằng "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Chuỗi không hợp lệ: phải bao gồm "${_issue.includes}"`; - if (_issue.format === "regex") - return `Chuỗi không hợp lệ: phải khớp với mẫu ${_issue.pattern}`; - return `${Nouns[_issue.format] ?? issue.format} không hợp lệ`; - } - case "not_multiple_of": - return `Số không hợp lệ: phải là bội số của ${issue.divisor}`; - case "unrecognized_keys": - return `Khóa không được nhận dạng: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Khóa không hợp lệ trong ${issue.origin}`; - case "invalid_union": - return "Đầu vào không hợp lệ"; - case "invalid_element": - return `Giá trị không hợp lệ trong ${issue.origin}`; - default: - return `Đầu vào không hợp lệ`; - } - }; -}; -/* harmony default export */ function vi() { - return { - localeError: vi_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/zh-CN.js - -const zh_CN_error = () => { - const Sizable = { - string: { unit: "字符", verb: "包含" }, - file: { unit: "字节", verb: "包含" }, - array: { unit: "项", verb: "包含" }, - set: { unit: "项", verb: "包含" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "非数字(NaN)" : "数字"; - } - case "object": { - if (Array.isArray(data)) { - return "数组"; - } - if (data === null) { - return "空值(null)"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "输入", - email: "电子邮件", - url: "URL", - emoji: "表情符号", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO日期时间", - date: "ISO日期", - time: "ISO时间", - duration: "ISO时长", - ipv4: "IPv4地址", - ipv6: "IPv6地址", - cidrv4: "IPv4网段", - cidrv6: "IPv6网段", - base64: "base64编码字符串", - base64url: "base64url编码字符串", - json_string: "JSON字符串", - e164: "E.164号码", - jwt: "JWT", - template_literal: "输入", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `无效输入:期望 ${issue.expected},实际接收 ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `无效输入:期望 ${stringifyPrimitive(issue.values[0])}`; - return `无效选项:期望以下之一 ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `数值过大:期望 ${issue.origin ?? "值"} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "个元素"}`; - return `数值过大:期望 ${issue.origin ?? "值"} ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `数值过小:期望 ${issue.origin} ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `数值过小:期望 ${issue.origin} ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `无效字符串:必须以 "${_issue.prefix}" 开头`; - if (_issue.format === "ends_with") - return `无效字符串:必须以 "${_issue.suffix}" 结尾`; - if (_issue.format === "includes") - return `无效字符串:必须包含 "${_issue.includes}"`; - if (_issue.format === "regex") - return `无效字符串:必须满足正则表达式 ${_issue.pattern}`; - return `无效${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `无效数字:必须是 ${issue.divisor} 的倍数`; - case "unrecognized_keys": - return `出现未知的键(key): ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `${issue.origin} 中的键(key)无效`; - case "invalid_union": - return "无效输入"; - case "invalid_element": - return `${issue.origin} 中包含无效值(value)`; - default: - return `无效输入`; - } - }; -}; -/* harmony default export */ function zh_CN() { - return { - localeError: zh_CN_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/zh-TW.js - -const zh_TW_error = () => { - const Sizable = { - string: { unit: "字元", verb: "擁有" }, - file: { unit: "位元組", verb: "擁有" }, - array: { unit: "項目", verb: "擁有" }, - set: { unit: "項目", verb: "擁有" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "number"; - } - case "object": { - if (Array.isArray(data)) { - return "array"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "輸入", - email: "郵件地址", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "ISO 日期時間", - date: "ISO 日期", - time: "ISO 時間", - duration: "ISO 期間", - ipv4: "IPv4 位址", - ipv6: "IPv6 位址", - cidrv4: "IPv4 範圍", - cidrv6: "IPv6 範圍", - base64: "base64 編碼字串", - base64url: "base64url 編碼字串", - json_string: "JSON 字串", - e164: "E.164 數值", - jwt: "JWT", - template_literal: "輸入", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `無效的輸入值:預期為 ${issue.expected},但收到 ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `無效的輸入值:預期為 ${stringifyPrimitive(issue.values[0])}`; - return `無效的選項:預期為以下其中之一 ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `數值過大:預期 ${issue.origin ?? "值"} 應為 ${adj}${issue.maximum.toString()} ${sizing.unit ?? "個元素"}`; - return `數值過大:預期 ${issue.origin ?? "值"} 應為 ${adj}${issue.maximum.toString()}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) { - return `數值過小:預期 ${issue.origin} 應為 ${adj}${issue.minimum.toString()} ${sizing.unit}`; - } - return `數值過小:預期 ${issue.origin} 應為 ${adj}${issue.minimum.toString()}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") { - return `無效的字串:必須以 "${_issue.prefix}" 開頭`; - } - if (_issue.format === "ends_with") - return `無效的字串:必須以 "${_issue.suffix}" 結尾`; - if (_issue.format === "includes") - return `無效的字串:必須包含 "${_issue.includes}"`; - if (_issue.format === "regex") - return `無效的字串:必須符合格式 ${_issue.pattern}`; - return `無效的 ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `無效的數字:必須為 ${issue.divisor} 的倍數`; - case "unrecognized_keys": - return `無法識別的鍵值${issue.keys.length > 1 ? "們" : ""}:${joinValues(issue.keys, "、")}`; - case "invalid_key": - return `${issue.origin} 中有無效的鍵值`; - case "invalid_union": - return "無效的輸入值"; - case "invalid_element": - return `${issue.origin} 中有無效的值`; - default: - return `無效的輸入值`; - } - }; -}; -/* harmony default export */ function zh_TW() { - return { - localeError: zh_TW_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/yo.js - -const yo_error = () => { - const Sizable = { - string: { unit: "àmi", verb: "ní" }, - file: { unit: "bytes", verb: "ní" }, - array: { unit: "nkan", verb: "ní" }, - set: { unit: "nkan", verb: "ní" }, - }; - function getSizing(origin) { - return Sizable[origin] ?? null; - } - const parsedType = (data) => { - const t = typeof data; - switch (t) { - case "number": { - return Number.isNaN(data) ? "NaN" : "nọ́mbà"; - } - case "object": { - if (Array.isArray(data)) { - return "akopọ"; - } - if (data === null) { - return "null"; - } - if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) { - return data.constructor.name; - } - } - } - return t; - }; - const Nouns = { - regex: "ẹ̀rọ ìbáwọlé", - email: "àdírẹ́sì ìmẹ́lì", - url: "URL", - emoji: "emoji", - uuid: "UUID", - uuidv4: "UUIDv4", - uuidv6: "UUIDv6", - nanoid: "nanoid", - guid: "GUID", - cuid: "cuid", - cuid2: "cuid2", - ulid: "ULID", - xid: "XID", - ksuid: "KSUID", - datetime: "àkókò ISO", - date: "ọjọ́ ISO", - time: "àkókò ISO", - duration: "àkókò tó pé ISO", - ipv4: "àdírẹ́sì IPv4", - ipv6: "àdírẹ́sì IPv6", - cidrv4: "àgbègbè IPv4", - cidrv6: "àgbègbè IPv6", - base64: "ọ̀rọ̀ tí a kọ́ ní base64", - base64url: "ọ̀rọ̀ base64url", - json_string: "ọ̀rọ̀ JSON", - e164: "nọ́mbà E.164", - jwt: "JWT", - template_literal: "ẹ̀rọ ìbáwọlé", - }; - return (issue) => { - switch (issue.code) { - case "invalid_type": - return `Ìbáwọlé aṣìṣe: a ní láti fi ${issue.expected}, àmọ̀ a rí ${parsedType(issue.input)}`; - case "invalid_value": - if (issue.values.length === 1) - return `Ìbáwọlé aṣìṣe: a ní láti fi ${stringifyPrimitive(issue.values[0])}`; - return `Àṣàyàn aṣìṣe: yan ọ̀kan lára ${joinValues(issue.values, "|")}`; - case "too_big": { - const adj = issue.inclusive ? "<=" : "<"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Tó pọ̀ jù: a ní láti jẹ́ pé ${issue.origin ?? "iye"} ${sizing.verb} ${adj}${issue.maximum} ${sizing.unit}`; - return `Tó pọ̀ jù: a ní láti jẹ́ ${adj}${issue.maximum}`; - } - case "too_small": { - const adj = issue.inclusive ? ">=" : ">"; - const sizing = getSizing(issue.origin); - if (sizing) - return `Kéré ju: a ní láti jẹ́ pé ${issue.origin} ${sizing.verb} ${adj}${issue.minimum} ${sizing.unit}`; - return `Kéré ju: a ní láti jẹ́ ${adj}${issue.minimum}`; - } - case "invalid_format": { - const _issue = issue; - if (_issue.format === "starts_with") - return `Ọ̀rọ̀ aṣìṣe: gbọ́dọ̀ bẹ̀rẹ̀ pẹ̀lú "${_issue.prefix}"`; - if (_issue.format === "ends_with") - return `Ọ̀rọ̀ aṣìṣe: gbọ́dọ̀ parí pẹ̀lú "${_issue.suffix}"`; - if (_issue.format === "includes") - return `Ọ̀rọ̀ aṣìṣe: gbọ́dọ̀ ní "${_issue.includes}"`; - if (_issue.format === "regex") - return `Ọ̀rọ̀ aṣìṣe: gbọ́dọ̀ bá àpẹẹrẹ mu ${_issue.pattern}`; - return `Aṣìṣe: ${Nouns[_issue.format] ?? issue.format}`; - } - case "not_multiple_of": - return `Nọ́mbà aṣìṣe: gbọ́dọ̀ jẹ́ èyà pípín ti ${issue.divisor}`; - case "unrecognized_keys": - return `Bọtìnì àìmọ̀: ${joinValues(issue.keys, ", ")}`; - case "invalid_key": - return `Bọtìnì aṣìṣe nínú ${issue.origin}`; - case "invalid_union": - return "Ìbáwọlé aṣìṣe"; - case "invalid_element": - return `Iye aṣìṣe nínú ${issue.origin}`; - default: - return "Ìbáwọlé aṣìṣe"; - } - }; -}; -/* harmony default export */ function yo() { - return { - localeError: yo_error(), - }; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/locales/index.js - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;// CONCATENATED MODULE: ./node_modules/zod/v4/core/registries.js -var _a; -const $output = Symbol("ZodOutput"); -const $input = Symbol("ZodInput"); -class $ZodRegistry { - constructor() { - this._map = new WeakMap(); - this._idmap = new Map(); - } - add(schema, ..._meta) { - const meta = _meta[0]; - this._map.set(schema, meta); - if (meta && typeof meta === "object" && "id" in meta) { - if (this._idmap.has(meta.id)) { - throw new Error(`ID ${meta.id} already exists in the registry`); - } - this._idmap.set(meta.id, schema); - } - return this; - } - clear() { - this._map = new WeakMap(); - this._idmap = new Map(); - return this; - } - remove(schema) { - const meta = this._map.get(schema); - if (meta && typeof meta === "object" && "id" in meta) { - this._idmap.delete(meta.id); - } - this._map.delete(schema); - return this; - } - get(schema) { - // return this._map.get(schema) as any; - // inherit metadata - const p = schema._zod.parent; - if (p) { - const pm = { ...(this.get(p) ?? {}) }; - delete pm.id; // do not inherit id - const f = { ...pm, ...this._map.get(schema) }; - return Object.keys(f).length ? f : undefined; - } - return this._map.get(schema); - } - has(schema) { - return this._map.has(schema); - } -} -// registries -function registry() { - return new $ZodRegistry(); -} -(_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry()); -const globalRegistry = globalThis.__zod_globalRegistry; - -;// CONCATENATED MODULE: ./node_modules/zod/v4/core/api.js - - - - -function _string(Class, params) { +function _float64(Class, params) { return new Class({ - type: "string", - ...normalizeParams(params), + type: "number", + check: "number_format", + abort: false, + format: "float64", + ...util.normalizeParams(params), }); } -function _coercedString(Class, params) { +function _int32(Class, params) { return new Class({ - type: "string", - coerce: true, - ...normalizeParams(params), + type: "number", + check: "number_format", + abort: false, + format: "int32", + ...util.normalizeParams(params), }); } -function _email(Class, params) { +function _uint32(Class, params) { return new Class({ - type: "string", - format: "email", - check: "string_format", + type: "number", + check: "number_format", abort: false, - ...normalizeParams(params), + format: "uint32", + ...util.normalizeParams(params), }); } -function _guid(Class, params) { +function _boolean(Class, params) { return new Class({ - type: "string", - format: "guid", - check: "string_format", - abort: false, + type: "boolean", ...normalizeParams(params), }); } -function _uuid(Class, params) { +function _coercedBoolean(Class, params) { return new Class({ - type: "string", - format: "uuid", - check: "string_format", - abort: false, - ...normalizeParams(params), + type: "boolean", + coerce: true, + ...util.normalizeParams(params), }); } -function _uuidv4(Class, params) { +function _bigint(Class, params) { return new Class({ - type: "string", - format: "uuid", - check: "string_format", - abort: false, - version: "v4", - ...normalizeParams(params), + type: "bigint", + ...util.normalizeParams(params), }); } -function _uuidv6(Class, params) { +function _coercedBigint(Class, params) { return new Class({ - type: "string", - format: "uuid", - check: "string_format", - abort: false, - version: "v6", - ...normalizeParams(params), + type: "bigint", + coerce: true, + ...util.normalizeParams(params), }); } -function _uuidv7(Class, params) { +function _int64(Class, params) { return new Class({ - type: "string", - format: "uuid", - check: "string_format", + type: "bigint", + check: "bigint_format", abort: false, - version: "v7", - ...normalizeParams(params), + format: "int64", + ...util.normalizeParams(params), }); } -function _url(Class, params) { +function _uint64(Class, params) { return new Class({ - type: "string", - format: "url", - check: "string_format", + type: "bigint", + check: "bigint_format", abort: false, - ...normalizeParams(params), + format: "uint64", + ...util.normalizeParams(params), }); } -function api_emoji(Class, params) { +function _symbol(Class, params) { return new Class({ - type: "string", - format: "emoji", - check: "string_format", - abort: false, - ...normalizeParams(params), + type: "symbol", + ...util.normalizeParams(params), }); } -function _nanoid(Class, params) { +function api_undefined(Class, params) { return new Class({ - type: "string", - format: "nanoid", - check: "string_format", - abort: false, - ...normalizeParams(params), + type: "undefined", + ...util.normalizeParams(params), }); } -function _cuid(Class, params) { +function api_null(Class, params) { return new Class({ - type: "string", - format: "cuid", - check: "string_format", - abort: false, - ...normalizeParams(params), + type: "null", + ...util.normalizeParams(params), }); } -function _cuid2(Class, params) { - return new Class({ - type: "string", - format: "cuid2", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _ulid(Class, params) { - return new Class({ - type: "string", - format: "ulid", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _xid(Class, params) { - return new Class({ - type: "string", - format: "xid", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _ksuid(Class, params) { - return new Class({ - type: "string", - format: "ksuid", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _ipv4(Class, params) { - return new Class({ - type: "string", - format: "ipv4", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _ipv6(Class, params) { - return new Class({ - type: "string", - format: "ipv6", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _mac(Class, params) { - return new Class({ - type: "string", - format: "mac", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _cidrv4(Class, params) { - return new Class({ - type: "string", - format: "cidrv4", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _cidrv6(Class, params) { - return new Class({ - type: "string", - format: "cidrv6", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _base64(Class, params) { - return new Class({ - type: "string", - format: "base64", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _base64url(Class, params) { - return new Class({ - type: "string", - format: "base64url", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _e164(Class, params) { - return new Class({ - type: "string", - format: "e164", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -function _jwt(Class, params) { - return new Class({ - type: "string", - format: "jwt", - check: "string_format", - abort: false, - ...normalizeParams(params), - }); -} -const TimePrecision = { - Any: null, - Minute: -1, - Second: 0, - Millisecond: 3, - Microsecond: 6, -}; -function _isoDateTime(Class, params) { - return new Class({ - type: "string", - format: "datetime", - check: "string_format", - offset: false, - local: false, - precision: null, - ...normalizeParams(params), - }); -} -function _isoDate(Class, params) { - return new Class({ - type: "string", - format: "date", - check: "string_format", - ...normalizeParams(params), - }); -} -function _isoTime(Class, params) { - return new Class({ - type: "string", - format: "time", - check: "string_format", - precision: null, - ...normalizeParams(params), - }); -} -function _isoDuration(Class, params) { - return new Class({ - type: "string", - format: "duration", - check: "string_format", - ...normalizeParams(params), - }); -} -function _number(Class, params) { - return new Class({ - type: "number", - checks: [], - ...normalizeParams(params), - }); -} -function _coercedNumber(Class, params) { - return new Class({ - type: "number", - coerce: true, - checks: [], - ...normalizeParams(params), - }); -} -function _int(Class, params) { - return new Class({ - type: "number", - check: "number_format", - abort: false, - format: "safeint", - ...normalizeParams(params), - }); -} -function _float32(Class, params) { - return new Class({ - type: "number", - check: "number_format", - abort: false, - format: "float32", - ...normalizeParams(params), - }); -} -function _float64(Class, params) { - return new Class({ - type: "number", - check: "number_format", - abort: false, - format: "float64", - ...normalizeParams(params), - }); -} -function _int32(Class, params) { - return new Class({ - type: "number", - check: "number_format", - abort: false, - format: "int32", - ...normalizeParams(params), - }); -} -function _uint32(Class, params) { - return new Class({ - type: "number", - check: "number_format", - abort: false, - format: "uint32", - ...normalizeParams(params), - }); -} -function _boolean(Class, params) { - return new Class({ - type: "boolean", - ...normalizeParams(params), - }); -} -function _coercedBoolean(Class, params) { - return new Class({ - type: "boolean", - coerce: true, - ...normalizeParams(params), - }); -} -function _bigint(Class, params) { - return new Class({ - type: "bigint", - ...normalizeParams(params), - }); -} -function _coercedBigint(Class, params) { - return new Class({ - type: "bigint", - coerce: true, - ...normalizeParams(params), - }); -} -function _int64(Class, params) { - return new Class({ - type: "bigint", - check: "bigint_format", - abort: false, - format: "int64", - ...normalizeParams(params), - }); -} -function _uint64(Class, params) { - return new Class({ - type: "bigint", - check: "bigint_format", - abort: false, - format: "uint64", - ...normalizeParams(params), - }); -} -function _symbol(Class, params) { - return new Class({ - type: "symbol", - ...normalizeParams(params), - }); -} -function api_undefined(Class, params) { - return new Class({ - type: "undefined", - ...normalizeParams(params), - }); -} -function api_null(Class, params) { - return new Class({ - type: "null", - ...normalizeParams(params), - }); -} -function _any(Class) { +function _any(Class) { return new Class({ type: "any", }); @@ -60822,26 +55273,26 @@ function _never(Class, params) { function _void(Class, params) { return new Class({ type: "void", - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _date(Class, params) { return new Class({ type: "date", - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _coercedDate(Class, params) { return new Class({ type: "date", coerce: true, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _nan(Class, params) { return new Class({ type: "nan", - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _lt(value, params) { @@ -60901,23 +55352,23 @@ function _multipleOf(value, params) { }); } function _maxSize(maximum, params) { - return new $ZodCheckMaxSize({ + return new checks.$ZodCheckMaxSize({ check: "max_size", - ...normalizeParams(params), + ...util.normalizeParams(params), maximum, }); } function _minSize(minimum, params) { - return new $ZodCheckMinSize({ + return new checks.$ZodCheckMinSize({ check: "min_size", - ...normalizeParams(params), + ...util.normalizeParams(params), minimum, }); } function _size(size, params) { - return new $ZodCheckSizeEquals({ + return new checks.$ZodCheckSizeEquals({ check: "size_equals", - ...normalizeParams(params), + ...util.normalizeParams(params), size, }); } @@ -60990,18 +55441,18 @@ function _endsWith(suffix, params) { }); } function _property(property, schema, params) { - return new $ZodCheckProperty({ + return new checks.$ZodCheckProperty({ check: "property", property, schema, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _mime(types, params) { - return new $ZodCheckMimeType({ + return new checks.$ZodCheckMimeType({ check: "mime_type", mime: types, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _overwrite(tx) { @@ -61026,10 +55477,6 @@ function _toLowerCase() { function _toUpperCase() { return _overwrite((input) => input.toUpperCase()); } -// slugify -function _slugify() { - return _overwrite((input) => slugify(input)); -} function _array(Class, element, params) { return new Class({ type: "array", @@ -61044,7 +55491,7 @@ function _union(Class, options, params) { return new Class({ type: "union", options, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _discriminatedUnion(Class, discriminator, options, params) { @@ -61052,7 +55499,7 @@ function _discriminatedUnion(Class, discriminator, options, params) { type: "union", options, discriminator, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _intersection(Class, left, right) { @@ -61068,14 +55515,14 @@ function _intersection(Class, left, right) { // params?: string | $ZodTupleParams // ): schemas.$ZodTuple<[], null>; function _tuple(Class, items, _paramsOrRest, _params) { - const hasRest = _paramsOrRest instanceof $ZodType; + const hasRest = _paramsOrRest instanceof schemas.$ZodType; const params = hasRest ? _params : _paramsOrRest; const rest = hasRest ? _paramsOrRest : null; return new Class({ type: "tuple", items, rest, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _record(Class, keyType, valueType, params) { @@ -61083,7 +55530,7 @@ function _record(Class, keyType, valueType, params) { type: "record", keyType, valueType, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _map(Class, keyType, valueType, params) { @@ -61091,14 +55538,14 @@ function _map(Class, keyType, valueType, params) { type: "map", keyType, valueType, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _set(Class, valueType, params) { return new Class({ type: "set", valueType, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _enum(Class, values, params) { @@ -61117,7 +55564,7 @@ function _enum(Class, values, params) { return new Class({ type: "enum", entries, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } /** @deprecated This API has been merged into `z.enum()`. Use `z.enum()` instead. @@ -61131,20 +55578,20 @@ function _nativeEnum(Class, entries, params) { return new Class({ type: "enum", entries, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _literal(Class, value, params) { return new Class({ type: "literal", values: Array.isArray(value) ? value : [value], - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _file(Class, params) { return new Class({ type: "file", - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _transform(Class, fn) { @@ -61170,7 +55617,7 @@ function _default(Class, innerType, defaultValue) { type: "default", innerType, get defaultValue() { - return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); + return typeof defaultValue === "function" ? defaultValue() : defaultValue; }, }); } @@ -61178,7 +55625,7 @@ function _nonoptional(Class, innerType, params) { return new Class({ type: "nonoptional", innerType, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _success(Class, innerType) { @@ -61211,7 +55658,7 @@ function _templateLiteral(Class, parts, params) { return new Class({ type: "template_literal", parts, - ...normalizeParams(params), + ...util.normalizeParams(params), }); } function _lazy(Class, getter) { @@ -61237,6 +55684,13 @@ function _custom(Class, fn, _params) { }); return schema; } +// export function _refine( +// Class: util.SchemaClass, +// fn: (arg: NoInfer) => util.MaybeAsync, +// _params: string | $ZodCustomParams = {} +// ): checks.$ZodCheck { +// return _custom(Class, fn, _params); +// } // same as _custom but defaults to abort:false function _refine(Class, fn, _params) { const schema = new Class({ @@ -61247,60 +55701,8 @@ function _refine(Class, fn, _params) { }); return schema; } -function _superRefine(fn) { - const ch = _check((payload) => { - payload.addIssue = (issue) => { - if (typeof issue === "string") { - payload.issues.push(util_issue(issue, payload.value, ch._zod.def)); - } - else { - // for Zod 3 backwards compatibility - const _issue = issue; - if (_issue.fatal) - _issue.continue = false; - _issue.code ?? (_issue.code = "custom"); - _issue.input ?? (_issue.input = payload.value); - _issue.inst ?? (_issue.inst = ch); - _issue.continue ?? (_issue.continue = !ch._zod.def.abort); // abort is always undefined, so this is always true... - payload.issues.push(util_issue(_issue)); - } - }; - return fn(payload.value, payload); - }); - return ch; -} -function _check(fn, params) { - const ch = new $ZodCheck({ - check: "custom", - ...normalizeParams(params), - }); - ch._zod.check = fn; - return ch; -} -function describe(description) { - const ch = new $ZodCheck({ check: "describe" }); - ch._zod.onattach = [ - (inst) => { - const existing = globalRegistry.get(inst) ?? {}; - globalRegistry.add(inst, { ...existing, description }); - }, - ]; - ch._zod.check = () => { }; // no-op check - return ch; -} -function meta(metadata) { - const ch = new $ZodCheck({ check: "meta" }); - ch._zod.onattach = [ - (inst) => { - const existing = globalRegistry.get(inst) ?? {}; - globalRegistry.add(inst, { ...existing, ...metadata }); - }, - ]; - ch._zod.check = () => { }; // no-op check - return ch; -} function _stringbool(Classes, _params) { - const params = normalizeParams(_params); + const params = util.normalizeParams(_params); let truthyArray = params.truthy ?? ["true", "1", "yes", "on", "y", "enabled"]; let falsyArray = params.falsy ?? ["false", "0", "no", "off", "n", "disabled"]; if (params.case !== "sensitive") { @@ -61309,16 +55711,13 @@ function _stringbool(Classes, _params) { } const truthySet = new Set(truthyArray); const falsySet = new Set(falsyArray); - const _Codec = Classes.Codec ?? $ZodCodec; - const _Boolean = Classes.Boolean ?? $ZodBoolean; - const _String = Classes.String ?? $ZodString; - const stringSchema = new _String({ type: "string", error: params.error }); - const booleanSchema = new _Boolean({ type: "boolean", error: params.error }); - const codec = new _Codec({ - type: "pipe", - in: stringSchema, - out: booleanSchema, - transform: ((input, payload) => { + const _Pipe = Classes.Pipe ?? schemas.$ZodPipe; + const _Boolean = Classes.Boolean ?? schemas.$ZodBoolean; + const _String = Classes.String ?? schemas.$ZodString; + const _Transform = Classes.Transform ?? schemas.$ZodTransform; + const tx = new _Transform({ + type: "transform", + transform: (input, payload) => { let data = input; if (params.case !== "sensitive") data = data.toLowerCase(); @@ -61334,28 +55733,35 @@ function _stringbool(Classes, _params) { expected: "stringbool", values: [...truthySet, ...falsySet], input: payload.value, - inst: codec, - continue: false, + inst: tx, }); return {}; } - }), - reverseTransform: ((input, _payload) => { - if (input === true) { - return truthyArray[0] || "true"; - } - else { - return falsyArray[0] || "false"; - } + }, + error: params.error, + }); + // params.error; + const innerPipe = new _Pipe({ + type: "pipe", + in: new _String({ type: "string", error: params.error }), + out: tx, + error: params.error, + }); + const outerPipe = new _Pipe({ + type: "pipe", + in: innerPipe, + out: new _Boolean({ + type: "boolean", + error: params.error, }), error: params.error, }); - return codec; + return outerPipe; } function _stringFormat(Class, format, fnOrRegex, _params = {}) { - const params = normalizeParams(_params); + const params = util.normalizeParams(_params); const def = { - ...normalizeParams(_params), + ...util.normalizeParams(_params), check: "string_format", type: "string", format, @@ -61369,17163 +55775,14793 @@ function _stringFormat(Class, format, fnOrRegex, _params = {}) { return inst; } -;// CONCATENATED MODULE: ./node_modules/zod/v4/core/to-json-schema.js +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/types/zod.js -class JSONSchemaGenerator { - constructor(params) { - this.counter = 0; - this.metadataRegistry = params?.metadata ?? globalRegistry; - this.target = params?.target ?? "draft-2020-12"; - this.unrepresentable = params?.unrepresentable ?? "throw"; - this.override = params?.override ?? (() => { }); - this.io = params?.io ?? "output"; - this.seen = new Map(); - } - process(schema, _params = { path: [], schemaPath: [] }) { - var _a; - const def = schema._zod.def; - const formatMap = { - guid: "uuid", - url: "uri", - datetime: "date-time", - json_string: "json-string", - regex: "", // do not set - }; - // check for schema in seens - const seen = this.seen.get(schema); - if (seen) { - seen.count++; - // check if cycle - const isCycle = _params.schemaPath.includes(schema); - if (isCycle) { - seen.cycle = _params.path; - } - return seen.schema; - } - // initialize - const result = { schema: {}, count: 1, cycle: undefined, path: _params.path }; - this.seen.set(schema, result); - // custom method overrides default behavior - const overrideSchema = schema._zod.toJSONSchema?.(); - if (overrideSchema) { - result.schema = overrideSchema; - } - else { - const params = { - ..._params, - schemaPath: [..._params.schemaPath, schema], - path: _params.path, - }; - const parent = schema._zod.parent; - if (parent) { - // schema was cloned from another schema - result.ref = parent; - this.process(parent, params); - this.seen.get(parent).isParent = true; - } - else { - const _json = result.schema; - switch (def.type) { - case "string": { - const json = _json; - json.type = "string"; - const { minimum, maximum, format, patterns, contentEncoding } = schema._zod - .bag; - if (typeof minimum === "number") - json.minLength = minimum; - if (typeof maximum === "number") - json.maxLength = maximum; - // custom pattern overrides format - if (format) { - json.format = formatMap[format] ?? format; - if (json.format === "") - delete json.format; // empty format is not valid - } - if (contentEncoding) - json.contentEncoding = contentEncoding; - if (patterns && patterns.size > 0) { - const regexes = [...patterns]; - if (regexes.length === 1) - json.pattern = regexes[0].source; - else if (regexes.length > 1) { - result.schema.allOf = [ - ...regexes.map((regex) => ({ - ...(this.target === "draft-7" || this.target === "draft-4" || this.target === "openapi-3.0" - ? { type: "string" } - : {}), - pattern: regex.source, - })), - ]; - } - } - break; - } - case "number": { - const json = _json; - const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; - if (typeof format === "string" && format.includes("int")) - json.type = "integer"; - else - json.type = "number"; - if (typeof exclusiveMinimum === "number") { - if (this.target === "draft-4" || this.target === "openapi-3.0") { - json.minimum = exclusiveMinimum; - json.exclusiveMinimum = true; - } - else { - json.exclusiveMinimum = exclusiveMinimum; - } - } - if (typeof minimum === "number") { - json.minimum = minimum; - if (typeof exclusiveMinimum === "number" && this.target !== "draft-4") { - if (exclusiveMinimum >= minimum) - delete json.minimum; - else - delete json.exclusiveMinimum; - } - } - if (typeof exclusiveMaximum === "number") { - if (this.target === "draft-4" || this.target === "openapi-3.0") { - json.maximum = exclusiveMaximum; - json.exclusiveMaximum = true; - } - else { - json.exclusiveMaximum = exclusiveMaximum; - } - } - if (typeof maximum === "number") { - json.maximum = maximum; - if (typeof exclusiveMaximum === "number" && this.target !== "draft-4") { - if (exclusiveMaximum <= maximum) - delete json.maximum; - else - delete json.exclusiveMaximum; - } - } - if (typeof multipleOf === "number") - json.multipleOf = multipleOf; - break; - } - case "boolean": { - const json = _json; - json.type = "boolean"; - break; - } - case "bigint": { - if (this.unrepresentable === "throw") { - throw new Error("BigInt cannot be represented in JSON Schema"); - } - break; - } - case "symbol": { - if (this.unrepresentable === "throw") { - throw new Error("Symbols cannot be represented in JSON Schema"); - } - break; - } - case "null": { - if (this.target === "openapi-3.0") { - _json.type = "string"; - _json.nullable = true; - _json.enum = [null]; - } - else - _json.type = "null"; - break; - } - case "any": { - break; - } - case "unknown": { - break; - } - case "undefined": { - if (this.unrepresentable === "throw") { - throw new Error("Undefined cannot be represented in JSON Schema"); - } - break; - } - case "void": { - if (this.unrepresentable === "throw") { - throw new Error("Void cannot be represented in JSON Schema"); - } - break; - } - case "never": { - _json.not = {}; - break; - } - case "date": { - if (this.unrepresentable === "throw") { - throw new Error("Date cannot be represented in JSON Schema"); - } - break; - } - case "array": { - const json = _json; - const { minimum, maximum } = schema._zod.bag; - if (typeof minimum === "number") - json.minItems = minimum; - if (typeof maximum === "number") - json.maxItems = maximum; - json.type = "array"; - json.items = this.process(def.element, { ...params, path: [...params.path, "items"] }); - break; - } - case "object": { - const json = _json; - json.type = "object"; - json.properties = {}; - const shape = def.shape; // params.shapeCache.get(schema)!; - for (const key in shape) { - json.properties[key] = this.process(shape[key], { - ...params, - path: [...params.path, "properties", key], - }); - } - // required keys - const allKeys = new Set(Object.keys(shape)); - // const optionalKeys = new Set(def.optional); - const requiredKeys = new Set([...allKeys].filter((key) => { - const v = def.shape[key]._zod; - if (this.io === "input") { - return v.optin === undefined; - } - else { - return v.optout === undefined; - } - })); - if (requiredKeys.size > 0) { - json.required = Array.from(requiredKeys); - } - // catchall - if (def.catchall?._zod.def.type === "never") { - // strict - json.additionalProperties = false; - } - else if (!def.catchall) { - // regular - if (this.io === "output") - json.additionalProperties = false; - } - else if (def.catchall) { - json.additionalProperties = this.process(def.catchall, { - ...params, - path: [...params.path, "additionalProperties"], - }); - } - break; - } - case "union": { - const json = _json; - // Discriminated unions use oneOf (exactly one match) instead of anyOf (one or more matches) - // because the discriminator field ensures mutual exclusivity between options in JSON Schema - const isDiscriminated = def.discriminator !== undefined; - const options = def.options.map((x, i) => this.process(x, { - ...params, - path: [...params.path, isDiscriminated ? "oneOf" : "anyOf", i], - })); - if (isDiscriminated) { - json.oneOf = options; - } - else { - json.anyOf = options; - } - break; - } - case "intersection": { - const json = _json; - const a = this.process(def.left, { - ...params, - path: [...params.path, "allOf", 0], - }); - const b = this.process(def.right, { - ...params, - path: [...params.path, "allOf", 1], - }); - const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; - const allOf = [ - ...(isSimpleIntersection(a) ? a.allOf : [a]), - ...(isSimpleIntersection(b) ? b.allOf : [b]), - ]; - json.allOf = allOf; - break; - } - case "tuple": { - const json = _json; - json.type = "array"; - const prefixPath = this.target === "draft-2020-12" ? "prefixItems" : "items"; - const restPath = this.target === "draft-2020-12" ? "items" : this.target === "openapi-3.0" ? "items" : "additionalItems"; - const prefixItems = def.items.map((x, i) => this.process(x, { - ...params, - path: [...params.path, prefixPath, i], - })); - const rest = def.rest - ? this.process(def.rest, { - ...params, - path: [...params.path, restPath, ...(this.target === "openapi-3.0" ? [def.items.length] : [])], - }) - : null; - if (this.target === "draft-2020-12") { - json.prefixItems = prefixItems; - if (rest) { - json.items = rest; - } - } - else if (this.target === "openapi-3.0") { - json.items = { - anyOf: prefixItems, - }; - if (rest) { - json.items.anyOf.push(rest); - } - json.minItems = prefixItems.length; - if (!rest) { - json.maxItems = prefixItems.length; - } - } - else { - json.items = prefixItems; - if (rest) { - json.additionalItems = rest; - } - } - // length - const { minimum, maximum } = schema._zod.bag; - if (typeof minimum === "number") - json.minItems = minimum; - if (typeof maximum === "number") - json.maxItems = maximum; - break; - } - case "record": { - const json = _json; - json.type = "object"; - if (this.target === "draft-7" || this.target === "draft-2020-12") { - json.propertyNames = this.process(def.keyType, { - ...params, - path: [...params.path, "propertyNames"], - }); - } - json.additionalProperties = this.process(def.valueType, { - ...params, - path: [...params.path, "additionalProperties"], - }); - break; - } - case "map": { - if (this.unrepresentable === "throw") { - throw new Error("Map cannot be represented in JSON Schema"); - } - break; - } - case "set": { - if (this.unrepresentable === "throw") { - throw new Error("Set cannot be represented in JSON Schema"); - } - break; - } - case "enum": { - const json = _json; - const values = getEnumValues(def.entries); - // Number enums can have both string and number values - if (values.every((v) => typeof v === "number")) - json.type = "number"; - if (values.every((v) => typeof v === "string")) - json.type = "string"; - json.enum = values; - break; - } - case "literal": { - const json = _json; - const vals = []; - for (const val of def.values) { - if (val === undefined) { - if (this.unrepresentable === "throw") { - throw new Error("Literal `undefined` cannot be represented in JSON Schema"); - } - else { - // do not add to vals - } - } - else if (typeof val === "bigint") { - if (this.unrepresentable === "throw") { - throw new Error("BigInt literals cannot be represented in JSON Schema"); - } - else { - vals.push(Number(val)); - } - } - else { - vals.push(val); - } - } - if (vals.length === 0) { - // do nothing (an undefined literal was stripped) - } - else if (vals.length === 1) { - const val = vals[0]; - json.type = val === null ? "null" : typeof val; - if (this.target === "draft-4" || this.target === "openapi-3.0") { - json.enum = [val]; - } - else { - json.const = val; - } - } - else { - if (vals.every((v) => typeof v === "number")) - json.type = "number"; - if (vals.every((v) => typeof v === "string")) - json.type = "string"; - if (vals.every((v) => typeof v === "boolean")) - json.type = "string"; - if (vals.every((v) => v === null)) - json.type = "null"; - json.enum = vals; - } - break; - } - case "file": { - const json = _json; - const file = { - type: "string", - format: "binary", - contentEncoding: "binary", - }; - const { minimum, maximum, mime } = schema._zod.bag; - if (minimum !== undefined) - file.minLength = minimum; - if (maximum !== undefined) - file.maxLength = maximum; - if (mime) { - if (mime.length === 1) { - file.contentMediaType = mime[0]; - Object.assign(json, file); - } - else { - json.anyOf = mime.map((m) => { - const mFile = { ...file, contentMediaType: m }; - return mFile; - }); - } - } - else { - Object.assign(json, file); - } - // if (this.unrepresentable === "throw") { - // throw new Error("File cannot be represented in JSON Schema"); - // } - break; - } - case "transform": { - if (this.unrepresentable === "throw") { - throw new Error("Transforms cannot be represented in JSON Schema"); - } - break; - } - case "nullable": { - const inner = this.process(def.innerType, params); - if (this.target === "openapi-3.0") { - result.ref = def.innerType; - _json.nullable = true; - } - else { - _json.anyOf = [inner, { type: "null" }]; - } - break; - } - case "nonoptional": { - this.process(def.innerType, params); - result.ref = def.innerType; - break; - } - case "success": { - const json = _json; - json.type = "boolean"; - break; - } - case "default": { - this.process(def.innerType, params); - result.ref = def.innerType; - _json.default = JSON.parse(JSON.stringify(def.defaultValue)); - break; - } - case "prefault": { - this.process(def.innerType, params); - result.ref = def.innerType; - if (this.io === "input") - _json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); - break; - } - case "catch": { - // use conditionals - this.process(def.innerType, params); - result.ref = def.innerType; - let catchValue; - try { - catchValue = def.catchValue(undefined); - } - catch { - throw new Error("Dynamic catch values are not supported in JSON Schema"); - } - _json.default = catchValue; - break; - } - case "nan": { - if (this.unrepresentable === "throw") { - throw new Error("NaN cannot be represented in JSON Schema"); - } - break; - } - case "template_literal": { - const json = _json; - const pattern = schema._zod.pattern; - if (!pattern) - throw new Error("Pattern not found in template literal"); - json.type = "string"; - json.pattern = pattern.source; - break; - } - case "pipe": { - const innerType = this.io === "input" ? (def.in._zod.def.type === "transform" ? def.out : def.in) : def.out; - this.process(innerType, params); - result.ref = innerType; - break; - } - case "readonly": { - this.process(def.innerType, params); - result.ref = def.innerType; - _json.readOnly = true; - break; - } - // passthrough types - case "promise": { - this.process(def.innerType, params); - result.ref = def.innerType; - break; - } - case "optional": { - this.process(def.innerType, params); - result.ref = def.innerType; - break; - } - case "lazy": { - const innerType = schema._zod.innerType; - this.process(innerType, params); - result.ref = innerType; - break; - } - case "custom": { - if (this.unrepresentable === "throw") { - throw new Error("Custom types cannot be represented in JSON Schema"); - } - break; - } - case "function": { - if (this.unrepresentable === "throw") { - throw new Error("Function types cannot be represented in JSON Schema"); - } - break; - } - default: { - def; - } - } - } - } - // metadata - const meta = this.metadataRegistry.get(schema); - if (meta) - Object.assign(result.schema, meta); - if (this.io === "input" && isTransforming(schema)) { - // examples/defaults only apply to output type of pipe - delete result.schema.examples; - delete result.schema.default; - } - // set prefault as default - if (this.io === "input" && result.schema._prefault) - (_a = result.schema).default ?? (_a.default = result.schema._prefault); - delete result.schema._prefault; - // pulling fresh from this.seen in case it was overwritten - const _result = this.seen.get(schema); - return _result.schema; - } - emit(schema, _params) { - const params = { - cycles: _params?.cycles ?? "ref", - reused: _params?.reused ?? "inline", - // unrepresentable: _params?.unrepresentable ?? "throw", - // uri: _params?.uri ?? ((id) => `${id}`), - external: _params?.external ?? undefined, - }; - // iterate over seen map; - const root = this.seen.get(schema); - if (!root) - throw new Error("Unprocessed schema. This is a bug in Zod."); - // initialize result with root schema fields - // Object.assign(result, seen.cached); - // returns a ref to the schema - // defId will be empty if the ref points to an external schema (or #) - const makeURI = (entry) => { - // comparing the seen objects because sometimes - // multiple schemas map to the same seen object. - // e.g. lazy - // external is configured - const defsSegment = this.target === "draft-2020-12" ? "$defs" : "definitions"; - if (params.external) { - const externalId = params.external.registry.get(entry[0])?.id; // ?? "__shared";// `__schema${this.counter++}`; - // check if schema is in the external registry - const uriGenerator = params.external.uri ?? ((id) => id); - if (externalId) { - return { ref: uriGenerator(externalId) }; - } - // otherwise, add to __shared - const id = entry[1].defId ?? entry[1].schema.id ?? `schema${this.counter++}`; - entry[1].defId = id; // set defId so it will be reused if needed - return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` }; - } - if (entry[1] === root) { - return { ref: "#" }; - } - // self-contained schema - const uriPrefix = `#`; - const defUriPrefix = `${uriPrefix}/${defsSegment}/`; - const defId = entry[1].schema.id ?? `__schema${this.counter++}`; - return { defId, ref: defUriPrefix + defId }; - }; - // stored cached version in `def` property - // remove all properties, set $ref - const extractToDef = (entry) => { - // if the schema is already a reference, do not extract it - if (entry[1].schema.$ref) { - return; - } - const seen = entry[1]; - const { ref, defId } = makeURI(entry); - seen.def = { ...seen.schema }; - // defId won't be set if the schema is a reference to an external schema - if (defId) - seen.defId = defId; - // wipe away all properties except $ref - const schema = seen.schema; - for (const key in schema) { - delete schema[key]; - } - schema.$ref = ref; - }; - // throw on cycles - // break cycles - if (params.cycles === "throw") { - for (const entry of this.seen.entries()) { - const seen = entry[1]; - if (seen.cycle) { - throw new Error("Cycle detected: " + - `#/${seen.cycle?.join("/")}/` + - '\n\nSet the `cycles` parameter to `"ref"` to resolve cyclical schemas with defs.'); - } - } - } - // extract schemas into $defs - for (const entry of this.seen.entries()) { - const seen = entry[1]; - // convert root schema to # $ref - if (schema === entry[0]) { - extractToDef(entry); // this has special handling for the root schema - continue; - } - // extract schemas that are in the external registry - if (params.external) { - const ext = params.external.registry.get(entry[0])?.id; - if (schema !== entry[0] && ext) { - extractToDef(entry); - continue; - } - } - // extract schemas with `id` meta - const id = this.metadataRegistry.get(entry[0])?.id; - if (id) { - extractToDef(entry); - continue; - } - // break cycles - if (seen.cycle) { - // any - extractToDef(entry); - continue; - } - // extract reused schemas - if (seen.count > 1) { - if (params.reused === "ref") { - extractToDef(entry); - // biome-ignore lint: - continue; - } - } - } - // flatten _refs - const flattenRef = (zodSchema, params) => { - const seen = this.seen.get(zodSchema); - const schema = seen.def ?? seen.schema; - const _cached = { ...schema }; - // already seen - if (seen.ref === null) { - return; - } - // flatten ref if defined - const ref = seen.ref; - seen.ref = null; // prevent recursion - if (ref) { - flattenRef(ref, params); - // merge referenced schema into current - const refSchema = this.seen.get(ref).schema; - if (refSchema.$ref && - (params.target === "draft-7" || params.target === "draft-4" || params.target === "openapi-3.0")) { - schema.allOf = schema.allOf ?? []; - schema.allOf.push(refSchema); - } - else { - Object.assign(schema, refSchema); - Object.assign(schema, _cached); // prevent overwriting any fields in the original schema - } - } - // execute overrides - if (!seen.isParent) - this.override({ - zodSchema: zodSchema, - jsonSchema: schema, - path: seen.path ?? [], - }); - }; - for (const entry of [...this.seen.entries()].reverse()) { - flattenRef(entry[0], { target: this.target }); - } - const result = {}; - if (this.target === "draft-2020-12") { - result.$schema = "https://json-schema.org/draft/2020-12/schema"; - } - else if (this.target === "draft-7") { - result.$schema = "http://json-schema.org/draft-07/schema#"; - } - else if (this.target === "draft-4") { - result.$schema = "http://json-schema.org/draft-04/schema#"; - } - else if (this.target === "openapi-3.0") { - // OpenAPI 3.0 schema objects should not include a $schema property - } - else { - // @ts-ignore - console.warn(`Invalid target: ${this.target}`); - } - if (params.external?.uri) { - const id = params.external.registry.get(schema)?.id; - if (!id) - throw new Error("Schema is missing an `id` property"); - result.$id = params.external.uri(id); - } - Object.assign(result, root.def); - // build defs object - const defs = params.external?.defs ?? {}; - for (const entry of this.seen.entries()) { - const seen = entry[1]; - if (seen.def && seen.defId) { - defs[seen.defId] = seen.def; - } - } - // set definitions in result - if (params.external) { - } - else { - if (Object.keys(defs).length > 0) { - if (this.target === "draft-2020-12") { - result.$defs = defs; - } - else { - result.definitions = defs; - } - } - } - try { - // this "finalizes" this schema and ensures all cycles are removed - // each call to .emit() is functionally independent - // though the seen map is shared - return JSON.parse(JSON.stringify(result)); - } - catch (_err) { - throw new Error("Error converting schema to JSON."); - } - } -} -function toJSONSchema(input, _params) { - if (input instanceof $ZodRegistry) { - const gen = new JSONSchemaGenerator(_params); - const defs = {}; - for (const entry of input._idmap.entries()) { - const [_, schema] = entry; - gen.process(schema); - } - const schemas = {}; - const external = { - registry: input, - uri: _params?.uri, - defs, - }; - for (const entry of input._idmap.entries()) { - const [key, schema] = entry; - schemas[key] = gen.emit(schema, { - ..._params, - external, - }); - } - if (Object.keys(defs).length > 0) { - const defsSegment = gen.target === "draft-2020-12" ? "$defs" : "definitions"; - schemas.__shared = { - [defsSegment]: defs, - }; - } - return { schemas }; - } - const gen = new JSONSchemaGenerator(_params); - gen.process(input); - return gen.emit(input, _params); -} -function isTransforming(_schema, _ctx) { - const ctx = _ctx ?? { seen: new Set() }; - if (ctx.seen.has(_schema)) - return false; - ctx.seen.add(_schema); - const def = _schema._zod.def; - if (def.type === "transform") - return true; - if (def.type === "array") - return isTransforming(def.element, ctx); - if (def.type === "set") - return isTransforming(def.valueType, ctx); - if (def.type === "lazy") - return isTransforming(def.getter(), ctx); - if (def.type === "promise" || - def.type === "optional" || - def.type === "nonoptional" || - def.type === "nullable" || - def.type === "readonly" || - def.type === "default" || - def.type === "prefault") { - return isTransforming(def.innerType, ctx); - } - if (def.type === "intersection") { - return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); - } - if (def.type === "record" || def.type === "map") { - return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); - } - if (def.type === "pipe") { - return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); - } - if (def.type === "object") { - for (const key in def.shape) { - if (isTransforming(def.shape[key], ctx)) - return true; - } - return false; - } - if (def.type === "union") { - for (const option of def.options) { - if (isTransforming(option, ctx)) - return true; - } - return false; - } - if (def.type === "tuple") { - for (const item of def.items) { - if (isTransforming(item, ctx)) - return true; - } - if (def.rest && isTransforming(def.rest, ctx)) - return true; - return false; - } - return false; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/core/json-schema.js - - -;// CONCATENATED MODULE: ./node_modules/zod/v4/core/index.js - - - - - - - - - - - - - - - -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/types/zod.js - - -//#region src/utils/types/zod.ts -function isZodSchemaV4(schema) { - if (typeof schema !== "object" || schema === null) return false; - const obj = schema; - if (!("_zod" in obj)) return false; - const zod = obj._zod; - return typeof zod === "object" && zod !== null && "def" in zod; -} -function isZodSchemaV3(schema) { - if (typeof schema !== "object" || schema === null) return false; - const obj = schema; - if (!("_def" in obj) || "_zod" in obj) return false; - const def = obj._def; - return typeof def === "object" && def != null && "typeName" in def; -} -/** Backward compatible isZodSchema for Zod 3 */ -function isZodSchema(schema) { - if (isZodSchemaV4(schema)) console.warn("[WARNING] Attempting to use Zod 4 schema in a context where Zod 3 schema is expected. This may cause unexpected behavior."); - return isZodSchemaV3(schema); -} -/** -* Given either a Zod schema, or plain object, determine if the input is a Zod schema. -* -* @param {unknown} input -* @returns {boolean} Whether or not the provided input is a Zod schema. -*/ -function isInteropZodSchema(input) { - if (!input) return false; - if (typeof input !== "object") return false; - if (Array.isArray(input)) return false; - if (isZodSchemaV4(input) || isZodSchemaV3(input)) return true; - return false; -} -function isZodLiteralV3(obj) { - if (typeof obj === "object" && obj !== null && "_def" in obj && typeof obj._def === "object" && obj._def !== null && "typeName" in obj._def && obj._def.typeName === "ZodLiteral") return true; - return false; -} -function isZodLiteralV4(obj) { - if (!isZodSchemaV4(obj)) return false; - if (typeof obj === "object" && obj !== null && "_zod" in obj && typeof obj._zod === "object" && obj._zod !== null && "def" in obj._zod && typeof obj._zod.def === "object" && obj._zod.def !== null && "type" in obj._zod.def && obj._zod.def.type === "literal") return true; - return false; -} -/** -* Determines if the provided value is an InteropZodLiteral (Zod v3 or v4 literal schema). -* -* @param obj The value to check. -* @returns {boolean} True if the value is a Zod v3 or v4 literal schema, false otherwise. -*/ -function isInteropZodLiteral(obj) { - if (isZodLiteralV3(obj)) return true; - if (isZodLiteralV4(obj)) return true; - return false; -} -/** -* Asynchronously parses the input using the provided Zod schema (v3 or v4) and returns a safe parse result. -* This function handles both Zod v3 and v4 schemas, returning a result object indicating success or failure. -* -* @template T - The expected output type of the schema. -* @param {InteropZodType} schema - The Zod schema (v3 or v4) to use for parsing. -* @param {unknown} input - The input value to parse. -* @returns {Promise>} A promise that resolves to a safe parse result object. -* @throws {Error} If the schema is not a recognized Zod v3 or v4 schema. -*/ -async function interopSafeParseAsync(schema, input) { - if (isZodSchemaV4(schema)) try { - const data = await parseAsync(schema, input); - return { - success: true, - data - }; - } catch (error) { - return { - success: false, - error - }; - } - if (isZodSchemaV3(schema)) return await schema.safeParseAsync(input); - throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); -} -/** -* Asynchronously parses the input using the provided Zod schema (v3 or v4) and returns the parsed value. -* Throws an error if parsing fails or if the schema is not a recognized Zod v3 or v4 schema. -* -* @template T - The expected output type of the schema. -* @param {InteropZodType} schema - The Zod schema (v3 or v4) to use for parsing. -* @param {unknown} input - The input value to parse. -* @returns {Promise} A promise that resolves to the parsed value. -* @throws {Error} If parsing fails or the schema is not a recognized Zod v3 or v4 schema. -*/ -async function interopParseAsync(schema, input) { - if (isZodSchemaV4(schema)) return await parseAsync(schema, input); - if (isZodSchemaV3(schema)) return await schema.parseAsync(input); - throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); -} -/** -* Safely parses the input using the provided Zod schema (v3 or v4) and returns a result object -* indicating success or failure. This function is compatible with both Zod v3 and v4 schemas. -* -* @template T - The expected output type of the schema. -* @param {InteropZodType} schema - The Zod schema (v3 or v4) to use for parsing. -* @param {unknown} input - The input value to parse. -* @returns {InteropZodSafeParseResult} An object with either the parsed data (on success) -* or the error (on failure). -* @throws {Error} If the schema is not a recognized Zod v3 or v4 schema. -*/ -function interopSafeParse(schema, input) { - if (isZodSchemaV4(schema)) try { - const data = parse_parse(schema, input); - return { - success: true, - data - }; - } catch (error) { - return { - success: false, - error - }; - } - if (isZodSchemaV3(schema)) return schema.safeParse(input); - throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); -} -/** -* Parses the input using the provided Zod schema (v3 or v4) and returns the parsed value. -* Throws an error if parsing fails or if the schema is not a recognized Zod v3 or v4 schema. -* -* @template T - The expected output type of the schema. -* @param {InteropZodType} schema - The Zod schema (v3 or v4) to use for parsing. -* @param {unknown} input - The input value to parse. -* @returns {T} The parsed value. -* @throws {Error} If parsing fails or the schema is not a recognized Zod v3 or v4 schema. -*/ -function interopParse(schema, input) { - if (isZodSchemaV4(schema)) return parse_parse(schema, input); - if (isZodSchemaV3(schema)) return schema.parse(input); - throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); -} -/** -* Retrieves the description from a schema definition (v3, v4, or plain object), if available. -* -* @param {unknown} schema - The schema to extract the description from. -* @returns {string | undefined} The description of the schema, or undefined if not present. -*/ -function getSchemaDescription(schema) { - if (isZodSchemaV4(schema)) return globalRegistry.get(schema)?.description; - if (isZodSchemaV3(schema)) return schema.description; - if ("description" in schema && typeof schema.description === "string") return schema.description; - return void 0; -} -/** -* Determines if the provided Zod schema is "shapeless". -* A shapeless schema is one that does not define any object shape, -* such as ZodString, ZodNumber, ZodBoolean, ZodAny, etc. -* For ZodObject, it must have no shape keys to be considered shapeless. -* ZodRecord schemas are considered shapeless since they define dynamic -* key-value mappings without fixed keys. -* -* @param schema The Zod schema to check. -* @returns {boolean} True if the schema is shapeless, false otherwise. -*/ -function isShapelessZodSchema(schema) { - if (!isInteropZodSchema(schema)) return false; - if (isZodSchemaV3(schema)) { - const def = schema._def; - if (def.typeName === "ZodObject") { - const obj = schema; - return !obj.shape || Object.keys(obj.shape).length === 0; - } - if (def.typeName === "ZodRecord") return true; - } - if (isZodSchemaV4(schema)) { - const def = schema._zod.def; - if (def.type === "object") { - const obj = schema; - return !obj.shape || Object.keys(obj.shape).length === 0; - } - if (def.type === "record") return true; - } - if (typeof schema === "object" && schema !== null && !("shape" in schema)) return true; - return false; -} -/** -* Determines if the provided Zod schema should be treated as a simple string schema -* that maps to DynamicTool. This aligns with the type-level constraint of -* InteropZodType which only matches basic string schemas. -* If the provided schema is just z.string(), we can make the determination that -* the tool is just a generic string tool that doesn't require any input validation. -* -* This function only returns true for basic ZodString schemas, including: -* - Basic string schemas (z.string()) -* - String schemas with validations (z.string().min(1), z.string().email(), etc.) -* -* This function returns false for everything else, including: -* - String schemas with defaults (z.string().default("value")) -* - Branded string schemas (z.string().brand<"UserId">()) -* - String schemas with catch operations (z.string().catch("default")) -* - Optional/nullable string schemas (z.string().optional()) -* - Transformed schemas (z.string().transform() or z.object().transform()) -* - Object or record schemas, even if they're empty -* - Any other schema type -* -* @param schema The Zod schema to check. -* @returns {boolean} True if the schema is a basic ZodString, false otherwise. -*/ -function isSimpleStringZodSchema(schema) { - if (!isInteropZodSchema(schema)) return false; - if (isZodSchemaV3(schema)) { - const def = schema._def; - return def.typeName === "ZodString"; - } - if (isZodSchemaV4(schema)) { - const def = schema._zod.def; - return def.type === "string"; - } - return false; -} -function isZodObjectV3(obj) { - if (typeof obj === "object" && obj !== null && "_def" in obj && typeof obj._def === "object" && obj._def !== null && "typeName" in obj._def && obj._def.typeName === "ZodObject") return true; - return false; -} -function isZodObjectV4(obj) { - if (!isZodSchemaV4(obj)) return false; - if (typeof obj === "object" && obj !== null && "_zod" in obj && typeof obj._zod === "object" && obj._zod !== null && "def" in obj._zod && typeof obj._zod.def === "object" && obj._zod.def !== null && "type" in obj._zod.def && obj._zod.def.type === "object") return true; - return false; -} -function isZodArrayV4(obj) { - if (!isZodSchemaV4(obj)) return false; - if (typeof obj === "object" && obj !== null && "_zod" in obj && typeof obj._zod === "object" && obj._zod !== null && "def" in obj._zod && typeof obj._zod.def === "object" && obj._zod.def !== null && "type" in obj._zod.def && obj._zod.def.type === "array") return true; - return false; -} -/** -* Determines if the provided value is an InteropZodObject (Zod v3 or v4 object schema). -* -* @param obj The value to check. -* @returns {boolean} True if the value is a Zod v3 or v4 object schema, false otherwise. -*/ -function isInteropZodObject(obj) { - if (isZodObjectV3(obj)) return true; - if (isZodObjectV4(obj)) return true; - return false; -} -/** -* Retrieves the shape (fields) of a Zod object schema, supporting both Zod v3 and v4. -* -* @template T - The type of the Zod object schema. -* @param {T} schema - The Zod object schema instance (either v3 or v4). -* @returns {InteropZodObjectShape} The shape of the object schema. -* @throws {Error} If the schema is not a Zod v3 or v4 object. -*/ -function getInteropZodObjectShape(schema) { - if (isZodSchemaV3(schema)) return schema.shape; - if (isZodSchemaV4(schema)) return schema._zod.def.shape; - throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); -} -/** -* Extends a Zod object schema with additional fields, supporting both Zod v3 and v4. -* -* @template T - The type of the Zod object schema. -* @param {T} schema - The Zod object schema instance (either v3 or v4). -* @param {InteropZodObjectShape} extension - The fields to add to the schema. -* @returns {InteropZodObject} The extended Zod object schema. -* @throws {Error} If the schema is not a Zod v3 or v4 object. -*/ -function extendInteropZodObject(schema, extension) { - if (isZodSchemaV3(schema)) return schema.extend(extension); - if (isZodSchemaV4(schema)) return extend(schema, extension); - throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); -} -/** -* Returns a partial version of a Zod object schema, making all fields optional. -* Supports both Zod v3 and v4. -* -* @template T - The type of the Zod object schema. -* @param {T} schema - The Zod object schema instance (either v3 or v4). -* @returns {InteropZodObject} The partial Zod object schema. -* @throws {Error} If the schema is not a Zod v3 or v4 object. -*/ -function interopZodObjectPartial(schema) { - if (isZodSchemaV3(schema)) return schema.partial(); - if (isZodSchemaV4(schema)) return partial($ZodOptional, schema, void 0); - throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); -} -/** -* Returns a strict version of a Zod object schema, disallowing unknown keys. -* Supports both Zod v3 and v4 object schemas. If `recursive` is true, applies strictness -* recursively to all nested object schemas and arrays of object schemas. -* -* @template T - The type of the Zod object schema. -* @param {T} schema - The Zod object schema instance (either v3 or v4). -* @param {boolean} [recursive=false] - Whether to apply strictness recursively to nested objects/arrays. -* @returns {InteropZodObject} The strict Zod object schema. -* @throws {Error} If the schema is not a Zod v3 or v4 object. -*/ -function interopZodObjectStrict(schema, recursive = false) { - if (isZodSchemaV3(schema)) return schema.strict(); - if (isZodObjectV4(schema)) { - const outputShape = schema._zod.def.shape; - if (recursive) for (const [key, keySchema] of Object.entries(schema._zod.def.shape)) { - if (isZodObjectV4(keySchema)) { - const outputSchema = interopZodObjectStrict(keySchema, recursive); - outputShape[key] = outputSchema; - } else if (isZodArrayV4(keySchema)) { - let elementSchema = keySchema._zod.def.element; - if (isZodObjectV4(elementSchema)) elementSchema = interopZodObjectStrict(elementSchema, recursive); - outputShape[key] = clone(keySchema, { - ...keySchema._zod.def, - element: elementSchema - }); - } else outputShape[key] = keySchema; - const meta$1 = globalRegistry.get(keySchema); - if (meta$1) globalRegistry.add(outputShape[key], meta$1); - } - const modifiedSchema = clone(schema, { - ...schema._zod.def, - shape: outputShape, - catchall: _never($ZodNever) - }); - const meta = globalRegistry.get(schema); - if (meta) globalRegistry.add(modifiedSchema, meta); - return modifiedSchema; - } - throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); -} -/** -* Returns a passthrough version of a Zod object schema, allowing unknown keys. -* Supports both Zod v3 and v4 object schemas. If `recursive` is true, applies passthrough -* recursively to all nested object schemas and arrays of object schemas. -* -* @template T - The type of the Zod object schema. -* @param {T} schema - The Zod object schema instance (either v3 or v4). -* @param {boolean} [recursive=false] - Whether to apply passthrough recursively to nested objects/arrays. -* @returns {InteropZodObject} The passthrough Zod object schema. -* @throws {Error} If the schema is not a Zod v3 or v4 object. -*/ -function interopZodObjectPassthrough(schema, recursive = false) { - if (isZodObjectV3(schema)) return schema.passthrough(); - if (isZodObjectV4(schema)) { - const outputShape = schema._zod.def.shape; - if (recursive) for (const [key, keySchema] of Object.entries(schema._zod.def.shape)) { - if (isZodObjectV4(keySchema)) { - const outputSchema = interopZodObjectPassthrough(keySchema, recursive); - outputShape[key] = outputSchema; - } else if (isZodArrayV4(keySchema)) { - let elementSchema = keySchema._zod.def.element; - if (isZodObjectV4(elementSchema)) elementSchema = interopZodObjectPassthrough(elementSchema, recursive); - outputShape[key] = clone(keySchema, { - ...keySchema._zod.def, - element: elementSchema - }); - } else outputShape[key] = keySchema; - const meta$1 = globalRegistry.get(keySchema); - if (meta$1) globalRegistry.add(outputShape[key], meta$1); - } - const modifiedSchema = clone(schema, { - ...schema._zod.def, - shape: outputShape, - catchall: _unknown($ZodUnknown) - }); - const meta = globalRegistry.get(schema); - if (meta) globalRegistry.add(modifiedSchema, meta); - return modifiedSchema; - } - throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); -} -/** -* Returns a getter function for the default value of a Zod schema, if one is defined. -* Supports both Zod v3 and v4 schemas. If the schema has a default value, -* the returned function will return that value when called. If no default is defined, -* returns undefined. -* -* @template T - The type of the Zod schema. -* @param {T} schema - The Zod schema instance (either v3 or v4). -* @returns {(() => InferInteropZodOutput) | undefined} A function that returns the default value, or undefined if no default is set. -*/ -function getInteropZodDefaultGetter(schema) { - if (isZodSchemaV3(schema)) try { - const defaultValue = schema.parse(void 0); - return () => defaultValue; - } catch { - return void 0; - } - if (isZodSchemaV4(schema)) try { - const defaultValue = parse_parse(schema, void 0); - return () => defaultValue; - } catch { - return void 0; - } - return void 0; -} -function isZodTransformV3(schema) { - return isZodSchemaV3(schema) && "typeName" in schema._def && schema._def.typeName === "ZodEffects"; -} -function isZodTransformV4(schema) { - return isZodSchemaV4(schema) && schema._zod.def.type === "pipe"; -} -function interopZodTransformInputSchemaImpl(schema, recursive, cache) { - const cached = cache.get(schema); - if (cached !== void 0) return cached; - if (isZodSchemaV3(schema)) { - if (isZodTransformV3(schema)) return interopZodTransformInputSchemaImpl(schema._def.schema, recursive, cache); - return schema; - } - if (isZodSchemaV4(schema)) { - let outputSchema = schema; - if (isZodTransformV4(schema)) outputSchema = interopZodTransformInputSchemaImpl(schema._zod.def.in, recursive, cache); - if (recursive) { - if (isZodObjectV4(outputSchema)) { - const outputShape = outputSchema._zod.def.shape; - for (const [key, keySchema] of Object.entries(outputSchema._zod.def.shape)) outputShape[key] = interopZodTransformInputSchemaImpl(keySchema, recursive, cache); - outputSchema = clone(outputSchema, { - ...outputSchema._zod.def, - shape: outputShape - }); - } else if (isZodArrayV4(outputSchema)) { - const elementSchema = interopZodTransformInputSchemaImpl(outputSchema._zod.def.element, recursive, cache); - outputSchema = clone(outputSchema, { - ...outputSchema._zod.def, - element: elementSchema - }); - } - } - const meta = globalRegistry.get(schema); - if (meta) globalRegistry.add(outputSchema, meta); - cache.set(schema, outputSchema); - return outputSchema; - } - throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); -} -/** -* Returns the input type of a Zod transform schema, for both v3 and v4. -* If the schema is not a transform, returns undefined. If `recursive` is true, -* recursively processes nested object schemas and arrays of object schemas. -* -* @param schema - The Zod schema instance (v3 or v4) -* @param {boolean} [recursive=false] - Whether to recursively process nested objects/arrays. -* @returns The input Zod schema of the transform, or undefined if not a transform -*/ -function interopZodTransformInputSchema(schema, recursive = false) { - const cache = /* @__PURE__ */ new WeakMap(); - return interopZodTransformInputSchemaImpl(schema, recursive, cache); -} -/** -* Creates a modified version of a Zod object schema where fields matching a predicate are made optional. -* Supports both Zod v3 and v4 schemas and preserves the original schema version. -* -* @template T - The type of the Zod object schema. -* @param {T} schema - The Zod object schema instance (either v3 or v4). -* @param {(key: string, value: InteropZodType) => boolean} predicate - Function to determine which fields should be optional. -* @returns {InteropZodObject} The modified Zod object schema. -* @throws {Error} If the schema is not a Zod v3 or v4 object. -*/ -function interopZodObjectMakeFieldsOptional(schema, predicate) { - if (isZodSchemaV3(schema)) { - const shape = getInteropZodObjectShape(schema); - const modifiedShape = {}; - for (const [key, value] of Object.entries(shape)) if (predicate(key, value)) modifiedShape[key] = value.optional(); - else modifiedShape[key] = value; - return schema.extend(modifiedShape); - } - if (isZodSchemaV4(schema)) { - const shape = getInteropZodObjectShape(schema); - const outputShape = { ...schema._zod.def.shape }; - for (const [key, value] of Object.entries(shape)) if (predicate(key, value)) outputShape[key] = new $ZodOptional({ - type: "optional", - innerType: value - }); - const modifiedSchema = clone(schema, { - ...schema._zod.def, - shape: outputShape - }); - const meta = globalRegistry.get(schema); - if (meta) globalRegistry.add(modifiedSchema, meta); - return modifiedSchema; - } - throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); -} -function isInteropZodError(e) { - return e instanceof Error && (e.constructor.name === "ZodError" || e.constructor.name === "$ZodError"); -} - -//#endregion - -//# sourceMappingURL=zod.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/Options.js -//#region src/utils/zod-to-json-schema/Options.ts -const ignoreOverride = Symbol("Let zodToJsonSchema decide on which parser to use"); -const Options_defaultOptions = { - name: void 0, - $refStrategy: "root", - basePath: ["#"], - effectStrategy: "input", - pipeStrategy: "all", - dateStrategy: "format:date-time", - mapStrategy: "entries", - removeAdditionalStrategy: "passthrough", - allowedAdditionalProperties: true, - rejectedAdditionalProperties: false, - definitionPath: "definitions", - target: "jsonSchema7", - strictUnions: false, - definitions: {}, - errorMessages: false, - markdownDescription: false, - patternStrategy: "escape", - applyRegexFlags: false, - emailStrategy: "format:email", - base64Strategy: "contentEncoding:base64", - nameStrategy: "ref", - openAiAnyTypeName: "OpenAiAnyType" -}; -const getDefaultOptions = (options) => typeof options === "string" ? { - ...Options_defaultOptions, - name: options -} : { - ...Options_defaultOptions, - ...options -}; - -//#endregion - -//# sourceMappingURL=Options.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/Refs.js - - -//#region src/utils/zod-to-json-schema/Refs.ts -const getRefs = (options) => { - const _options = getDefaultOptions(options); - const currentPath = _options.name !== void 0 ? [ - ..._options.basePath, - _options.definitionPath, - _options.name - ] : _options.basePath; - return { - ..._options, - flags: { hasReferencedOpenAiAnyType: false }, - currentPath, - propertyPath: void 0, - seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [def._def, { - def: def._def, - path: [ - ..._options.basePath, - _options.definitionPath, - name - ], - jsonSchema: void 0 - }])) - }; -}; - -//#endregion - -//# sourceMappingURL=Refs.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/getRelativePath.js -//#region src/utils/zod-to-json-schema/getRelativePath.ts -const getRelativePath = (pathA, pathB) => { - let i = 0; - for (; i < pathA.length && i < pathB.length; i++) if (pathA[i] !== pathB[i]) break; - return [(pathA.length - i).toString(), ...pathB.slice(i)].join("/"); -}; - -//#endregion - -//# sourceMappingURL=getRelativePath.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/any.js - - -//#region src/utils/zod-to-json-schema/parsers/any.ts -function parseAnyDef(refs) { - if (refs.target !== "openAi") return {}; - const anyDefinitionPath = [ - ...refs.basePath, - refs.definitionPath, - refs.openAiAnyTypeName - ]; - refs.flags.hasReferencedOpenAiAnyType = true; - return { $ref: refs.$refStrategy === "relative" ? getRelativePath(anyDefinitionPath, refs.currentPath) : anyDefinitionPath.join("/") }; -} - -//#endregion - -//# sourceMappingURL=any.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/errorMessages.js -//#region src/utils/zod-to-json-schema/errorMessages.ts -function addErrorMessage(res, key, errorMessage, refs) { - if (!refs?.errorMessages) return; - if (errorMessage) res.errorMessage = { - ...res.errorMessage, - [key]: errorMessage - }; -} -function setResponseValueAndErrors(res, key, value, errorMessage, refs) { - res[key] = value; - addErrorMessage(res, key, errorMessage, refs); -} - -//#endregion - -//# sourceMappingURL=errorMessages.js.map -;// CONCATENATED MODULE: ./node_modules/zod/v3/helpers/util.js -var util; -(function (util) { - util.assertEqual = (_) => { }; - function assertIs(_arg) { } - util.assertIs = assertIs; - function assertNever(_x) { - throw new Error(); - } - util.assertNever = assertNever; - util.arrayToEnum = (items) => { - const obj = {}; - for (const item of items) { - obj[item] = item; - } - return obj; - }; - util.getValidEnumValues = (obj) => { - const validKeys = util.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number"); - const filtered = {}; - for (const k of validKeys) { - filtered[k] = obj[k]; - } - return util.objectValues(filtered); - }; - util.objectValues = (obj) => { - return util.objectKeys(obj).map(function (e) { - return obj[e]; - }); - }; - util.objectKeys = typeof Object.keys === "function" // eslint-disable-line ban/ban - ? (obj) => Object.keys(obj) // eslint-disable-line ban/ban - : (object) => { - const keys = []; - for (const key in object) { - if (Object.prototype.hasOwnProperty.call(object, key)) { - keys.push(key); - } - } - return keys; - }; - util.find = (arr, checker) => { - for (const item of arr) { - if (checker(item)) - return item; - } - return undefined; - }; - util.isInteger = typeof Number.isInteger === "function" - ? (val) => Number.isInteger(val) // eslint-disable-line ban/ban - : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val; - function joinValues(array, separator = " | ") { - return array.map((val) => (typeof val === "string" ? `'${val}'` : val)).join(separator); - } - util.joinValues = joinValues; - util.jsonStringifyReplacer = (_, value) => { - if (typeof value === "bigint") { - return value.toString(); - } - return value; - }; -})(util || (util = {})); -var objectUtil; -(function (objectUtil) { - objectUtil.mergeShapes = (first, second) => { - return { - ...first, - ...second, // second overwrites first - }; - }; -})(objectUtil || (objectUtil = {})); -const ZodParsedType = util.arrayToEnum([ - "string", - "nan", - "number", - "integer", - "float", - "boolean", - "date", - "bigint", - "symbol", - "function", - "undefined", - "null", - "array", - "object", - "unknown", - "promise", - "void", - "never", - "map", - "set", -]); -const util_getParsedType = (data) => { - const t = typeof data; - switch (t) { - case "undefined": - return ZodParsedType.undefined; - case "string": - return ZodParsedType.string; - case "number": - return Number.isNaN(data) ? ZodParsedType.nan : ZodParsedType.number; - case "boolean": - return ZodParsedType.boolean; - case "function": - return ZodParsedType.function; - case "bigint": - return ZodParsedType.bigint; - case "symbol": - return ZodParsedType.symbol; - case "object": - if (Array.isArray(data)) { - return ZodParsedType.array; - } - if (data === null) { - return ZodParsedType.null; - } - if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") { - return ZodParsedType.promise; - } - if (typeof Map !== "undefined" && data instanceof Map) { - return ZodParsedType.map; - } - if (typeof Set !== "undefined" && data instanceof Set) { - return ZodParsedType.set; - } - if (typeof Date !== "undefined" && data instanceof Date) { - return ZodParsedType.date; - } - return ZodParsedType.object; - default: - return ZodParsedType.unknown; - } -}; - -;// CONCATENATED MODULE: ./node_modules/zod/v3/ZodError.js - -const ZodIssueCode = util.arrayToEnum([ - "invalid_type", - "invalid_literal", - "custom", - "invalid_union", - "invalid_union_discriminator", - "invalid_enum_value", - "unrecognized_keys", - "invalid_arguments", - "invalid_return_type", - "invalid_date", - "invalid_string", - "too_small", - "too_big", - "invalid_intersection_types", - "not_multiple_of", - "not_finite", -]); -const quotelessJson = (obj) => { - const json = JSON.stringify(obj, null, 2); - return json.replace(/"([^"]+)":/g, "$1:"); -}; -class ZodError extends Error { - get errors() { - return this.issues; - } - constructor(issues) { - super(); - this.issues = []; - this.addIssue = (sub) => { - this.issues = [...this.issues, sub]; - }; - this.addIssues = (subs = []) => { - this.issues = [...this.issues, ...subs]; - }; - const actualProto = new.target.prototype; - if (Object.setPrototypeOf) { - // eslint-disable-next-line ban/ban - Object.setPrototypeOf(this, actualProto); - } - else { - this.__proto__ = actualProto; - } - this.name = "ZodError"; - this.issues = issues; - } - format(_mapper) { - const mapper = _mapper || - function (issue) { - return issue.message; - }; - const fieldErrors = { _errors: [] }; - const processError = (error) => { - for (const issue of error.issues) { - if (issue.code === "invalid_union") { - issue.unionErrors.map(processError); - } - else if (issue.code === "invalid_return_type") { - processError(issue.returnTypeError); - } - else if (issue.code === "invalid_arguments") { - processError(issue.argumentsError); - } - else if (issue.path.length === 0) { - fieldErrors._errors.push(mapper(issue)); - } - else { - let curr = fieldErrors; - let i = 0; - while (i < issue.path.length) { - const el = issue.path[i]; - const terminal = i === issue.path.length - 1; - if (!terminal) { - curr[el] = curr[el] || { _errors: [] }; - // if (typeof el === "string") { - // curr[el] = curr[el] || { _errors: [] }; - // } else if (typeof el === "number") { - // const errorArray: any = []; - // errorArray._errors = []; - // curr[el] = curr[el] || errorArray; - // } - } - else { - curr[el] = curr[el] || { _errors: [] }; - curr[el]._errors.push(mapper(issue)); - } - curr = curr[el]; - i++; - } - } - } - }; - processError(this); - return fieldErrors; - } - static assert(value) { - if (!(value instanceof ZodError)) { - throw new Error(`Not a ZodError: ${value}`); - } - } - toString() { - return this.message; - } - get message() { - return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2); - } - get isEmpty() { - return this.issues.length === 0; - } - flatten(mapper = (issue) => issue.message) { - const fieldErrors = Object.create(null); - const formErrors = []; - for (const sub of this.issues) { - if (sub.path.length > 0) { - const firstEl = sub.path[0]; - fieldErrors[firstEl] = fieldErrors[firstEl] || []; - fieldErrors[firstEl].push(mapper(sub)); - } - else { - formErrors.push(mapper(sub)); - } - } - return { formErrors, fieldErrors }; - } - get formErrors() { - return this.flatten(); - } -} -ZodError.create = (issues) => { - const error = new ZodError(issues); - return error; -}; - -;// CONCATENATED MODULE: ./node_modules/zod/v3/locales/en.js - - -const errorMap = (issue, _ctx) => { - let message; - switch (issue.code) { - case ZodIssueCode.invalid_type: - if (issue.received === ZodParsedType.undefined) { - message = "Required"; - } - else { - message = `Expected ${issue.expected}, received ${issue.received}`; - } - break; - case ZodIssueCode.invalid_literal: - message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util.jsonStringifyReplacer)}`; - break; - case ZodIssueCode.unrecognized_keys: - message = `Unrecognized key(s) in object: ${util.joinValues(issue.keys, ", ")}`; - break; - case ZodIssueCode.invalid_union: - message = `Invalid input`; - break; - case ZodIssueCode.invalid_union_discriminator: - message = `Invalid discriminator value. Expected ${util.joinValues(issue.options)}`; - break; - case ZodIssueCode.invalid_enum_value: - message = `Invalid enum value. Expected ${util.joinValues(issue.options)}, received '${issue.received}'`; - break; - case ZodIssueCode.invalid_arguments: - message = `Invalid function arguments`; - break; - case ZodIssueCode.invalid_return_type: - message = `Invalid function return type`; - break; - case ZodIssueCode.invalid_date: - message = `Invalid date`; - break; - case ZodIssueCode.invalid_string: - if (typeof issue.validation === "object") { - if ("includes" in issue.validation) { - message = `Invalid input: must include "${issue.validation.includes}"`; - if (typeof issue.validation.position === "number") { - message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`; - } - } - else if ("startsWith" in issue.validation) { - message = `Invalid input: must start with "${issue.validation.startsWith}"`; - } - else if ("endsWith" in issue.validation) { - message = `Invalid input: must end with "${issue.validation.endsWith}"`; - } - else { - util.assertNever(issue.validation); - } - } - else if (issue.validation !== "regex") { - message = `Invalid ${issue.validation}`; - } - else { - message = "Invalid"; - } - break; - case ZodIssueCode.too_small: - if (issue.type === "array") - message = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`; - else if (issue.type === "string") - message = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`; - else if (issue.type === "number") - message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`; - else if (issue.type === "bigint") - message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`; - else if (issue.type === "date") - message = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`; - else - message = "Invalid input"; - break; - case ZodIssueCode.too_big: - if (issue.type === "array") - message = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`; - else if (issue.type === "string") - message = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`; - else if (issue.type === "number") - message = `Number must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`; - else if (issue.type === "bigint") - message = `BigInt must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`; - else if (issue.type === "date") - message = `Date must be ${issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`} ${new Date(Number(issue.maximum))}`; - else - message = "Invalid input"; - break; - case ZodIssueCode.custom: - message = `Invalid input`; - break; - case ZodIssueCode.invalid_intersection_types: - message = `Intersection results could not be merged`; - break; - case ZodIssueCode.not_multiple_of: - message = `Number must be a multiple of ${issue.multipleOf}`; - break; - case ZodIssueCode.not_finite: - message = "Number must be finite"; - break; - default: - message = _ctx.defaultError; - util.assertNever(issue); - } - return { message }; -}; -/* harmony default export */ const locales_en = (errorMap); - -;// CONCATENATED MODULE: ./node_modules/zod/v3/errors.js - -let overrideErrorMap = locales_en; - -function setErrorMap(map) { - overrideErrorMap = map; -} -function getErrorMap() { - return overrideErrorMap; -} - -;// CONCATENATED MODULE: ./node_modules/zod/v3/helpers/parseUtil.js - - -const makeIssue = (params) => { - const { data, path, errorMaps, issueData } = params; - const fullPath = [...path, ...(issueData.path || [])]; - const fullIssue = { - ...issueData, - path: fullPath, - }; - if (issueData.message !== undefined) { - return { - ...issueData, - path: fullPath, - message: issueData.message, - }; - } - let errorMessage = ""; - const maps = errorMaps - .filter((m) => !!m) - .slice() - .reverse(); - for (const map of maps) { - errorMessage = map(fullIssue, { data, defaultError: errorMessage }).message; - } - return { - ...issueData, - path: fullPath, - message: errorMessage, - }; -}; -const EMPTY_PATH = []; -function addIssueToContext(ctx, issueData) { - const overrideMap = getErrorMap(); - const issue = makeIssue({ - issueData: issueData, - data: ctx.data, - path: ctx.path, - errorMaps: [ - ctx.common.contextualErrorMap, // contextual error map is first priority - ctx.schemaErrorMap, // then schema-bound map if available - overrideMap, // then global override map - overrideMap === locales_en ? undefined : locales_en, // then global default map - ].filter((x) => !!x), - }); - ctx.common.issues.push(issue); -} -class ParseStatus { - constructor() { - this.value = "valid"; - } - dirty() { - if (this.value === "valid") - this.value = "dirty"; - } - abort() { - if (this.value !== "aborted") - this.value = "aborted"; - } - static mergeArray(status, results) { - const arrayValue = []; - for (const s of results) { - if (s.status === "aborted") - return INVALID; - if (s.status === "dirty") - status.dirty(); - arrayValue.push(s.value); - } - return { status: status.value, value: arrayValue }; - } - static async mergeObjectAsync(status, pairs) { - const syncPairs = []; - for (const pair of pairs) { - const key = await pair.key; - const value = await pair.value; - syncPairs.push({ - key, - value, - }); - } - return ParseStatus.mergeObjectSync(status, syncPairs); - } - static mergeObjectSync(status, pairs) { - const finalObject = {}; - for (const pair of pairs) { - const { key, value } = pair; - if (key.status === "aborted") - return INVALID; - if (value.status === "aborted") - return INVALID; - if (key.status === "dirty") - status.dirty(); - if (value.status === "dirty") - status.dirty(); - if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) { - finalObject[key.value] = value.value; - } - } - return { status: status.value, value: finalObject }; - } -} -const INVALID = Object.freeze({ - status: "aborted", -}); -const DIRTY = (value) => ({ status: "dirty", value }); -const OK = (value) => ({ status: "valid", value }); -const isAborted = (x) => x.status === "aborted"; -const isDirty = (x) => x.status === "dirty"; -const isValid = (x) => x.status === "valid"; -const isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise; - -;// CONCATENATED MODULE: ./node_modules/zod/v3/helpers/errorUtil.js -var errorUtil; -(function (errorUtil) { - errorUtil.errToObj = (message) => typeof message === "string" ? { message } : message || {}; - // biome-ignore lint: - errorUtil.toString = (message) => typeof message === "string" ? message : message?.message; -})(errorUtil || (errorUtil = {})); - -;// CONCATENATED MODULE: ./node_modules/zod/v3/types.js - - - - - -class ParseInputLazyPath { - constructor(parent, value, path, key) { - this._cachedPath = []; - this.parent = parent; - this.data = value; - this._path = path; - this._key = key; - } - get path() { - if (!this._cachedPath.length) { - if (Array.isArray(this._key)) { - this._cachedPath.push(...this._path, ...this._key); - } - else { - this._cachedPath.push(...this._path, this._key); - } - } - return this._cachedPath; - } -} -const handleResult = (ctx, result) => { - if (isValid(result)) { - return { success: true, data: result.value }; - } - else { - if (!ctx.common.issues.length) { - throw new Error("Validation failed but no issues detected."); - } - return { - success: false, - get error() { - if (this._error) - return this._error; - const error = new ZodError(ctx.common.issues); - this._error = error; - return this._error; - }, - }; - } -}; -function processCreateParams(params) { - if (!params) - return {}; - const { errorMap, invalid_type_error, required_error, description } = params; - if (errorMap && (invalid_type_error || required_error)) { - throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`); - } - if (errorMap) - return { errorMap: errorMap, description }; - const customMap = (iss, ctx) => { - const { message } = params; - if (iss.code === "invalid_enum_value") { - return { message: message ?? ctx.defaultError }; - } - if (typeof ctx.data === "undefined") { - return { message: message ?? required_error ?? ctx.defaultError }; - } - if (iss.code !== "invalid_type") - return { message: ctx.defaultError }; - return { message: message ?? invalid_type_error ?? ctx.defaultError }; - }; - return { errorMap: customMap, description }; -} -class ZodType { - get description() { - return this._def.description; - } - _getType(input) { - return util_getParsedType(input.data); - } - _getOrReturnCtx(input, ctx) { - return (ctx || { - common: input.parent.common, - data: input.data, - parsedType: util_getParsedType(input.data), - schemaErrorMap: this._def.errorMap, - path: input.path, - parent: input.parent, - }); - } - _processInputParams(input) { - return { - status: new ParseStatus(), - ctx: { - common: input.parent.common, - data: input.data, - parsedType: util_getParsedType(input.data), - schemaErrorMap: this._def.errorMap, - path: input.path, - parent: input.parent, - }, - }; - } - _parseSync(input) { - const result = this._parse(input); - if (isAsync(result)) { - throw new Error("Synchronous parse encountered promise."); - } - return result; - } - _parseAsync(input) { - const result = this._parse(input); - return Promise.resolve(result); - } - parse(data, params) { - const result = this.safeParse(data, params); - if (result.success) - return result.data; - throw result.error; - } - safeParse(data, params) { - const ctx = { - common: { - issues: [], - async: params?.async ?? false, - contextualErrorMap: params?.errorMap, - }, - path: params?.path || [], - schemaErrorMap: this._def.errorMap, - parent: null, - data, - parsedType: util_getParsedType(data), - }; - const result = this._parseSync({ data, path: ctx.path, parent: ctx }); - return handleResult(ctx, result); - } - "~validate"(data) { - const ctx = { - common: { - issues: [], - async: !!this["~standard"].async, - }, - path: [], - schemaErrorMap: this._def.errorMap, - parent: null, - data, - parsedType: util_getParsedType(data), - }; - if (!this["~standard"].async) { - try { - const result = this._parseSync({ data, path: [], parent: ctx }); - return isValid(result) - ? { - value: result.value, - } - : { - issues: ctx.common.issues, - }; - } - catch (err) { - if (err?.message?.toLowerCase()?.includes("encountered")) { - this["~standard"].async = true; - } - ctx.common = { - issues: [], - async: true, - }; - } - } - return this._parseAsync({ data, path: [], parent: ctx }).then((result) => isValid(result) - ? { - value: result.value, - } - : { - issues: ctx.common.issues, - }); - } - async parseAsync(data, params) { - const result = await this.safeParseAsync(data, params); - if (result.success) - return result.data; - throw result.error; - } - async safeParseAsync(data, params) { - const ctx = { - common: { - issues: [], - contextualErrorMap: params?.errorMap, - async: true, - }, - path: params?.path || [], - schemaErrorMap: this._def.errorMap, - parent: null, - data, - parsedType: util_getParsedType(data), - }; - const maybeAsyncResult = this._parse({ data, path: ctx.path, parent: ctx }); - const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult)); - return handleResult(ctx, result); - } - refine(check, message) { - const getIssueProperties = (val) => { - if (typeof message === "string" || typeof message === "undefined") { - return { message }; - } - else if (typeof message === "function") { - return message(val); - } - else { - return message; - } - }; - return this._refinement((val, ctx) => { - const result = check(val); - const setError = () => ctx.addIssue({ - code: ZodIssueCode.custom, - ...getIssueProperties(val), - }); - if (typeof Promise !== "undefined" && result instanceof Promise) { - return result.then((data) => { - if (!data) { - setError(); - return false; - } - else { - return true; - } - }); - } - if (!result) { - setError(); - return false; - } - else { - return true; - } - }); - } - refinement(check, refinementData) { - return this._refinement((val, ctx) => { - if (!check(val)) { - ctx.addIssue(typeof refinementData === "function" ? refinementData(val, ctx) : refinementData); - return false; - } - else { - return true; - } - }); - } - _refinement(refinement) { - return new ZodEffects({ - schema: this, - typeName: ZodFirstPartyTypeKind.ZodEffects, - effect: { type: "refinement", refinement }, - }); - } - superRefine(refinement) { - return this._refinement(refinement); - } - constructor(def) { - /** Alias of safeParseAsync */ - this.spa = this.safeParseAsync; - this._def = def; - this.parse = this.parse.bind(this); - this.safeParse = this.safeParse.bind(this); - this.parseAsync = this.parseAsync.bind(this); - this.safeParseAsync = this.safeParseAsync.bind(this); - this.spa = this.spa.bind(this); - this.refine = this.refine.bind(this); - this.refinement = this.refinement.bind(this); - this.superRefine = this.superRefine.bind(this); - this.optional = this.optional.bind(this); - this.nullable = this.nullable.bind(this); - this.nullish = this.nullish.bind(this); - this.array = this.array.bind(this); - this.promise = this.promise.bind(this); - this.or = this.or.bind(this); - this.and = this.and.bind(this); - this.transform = this.transform.bind(this); - this.brand = this.brand.bind(this); - this.default = this.default.bind(this); - this.catch = this.catch.bind(this); - this.describe = this.describe.bind(this); - this.pipe = this.pipe.bind(this); - this.readonly = this.readonly.bind(this); - this.isNullable = this.isNullable.bind(this); - this.isOptional = this.isOptional.bind(this); - this["~standard"] = { - version: 1, - vendor: "zod", - validate: (data) => this["~validate"](data), - }; - } - optional() { - return ZodOptional.create(this, this._def); - } - nullable() { - return ZodNullable.create(this, this._def); - } - nullish() { - return this.nullable().optional(); - } - array() { - return ZodArray.create(this); - } - promise() { - return ZodPromise.create(this, this._def); - } - or(option) { - return ZodUnion.create([this, option], this._def); - } - and(incoming) { - return ZodIntersection.create(this, incoming, this._def); - } - transform(transform) { - return new ZodEffects({ - ...processCreateParams(this._def), - schema: this, - typeName: ZodFirstPartyTypeKind.ZodEffects, - effect: { type: "transform", transform }, - }); - } - default(def) { - const defaultValueFunc = typeof def === "function" ? def : () => def; - return new ZodDefault({ - ...processCreateParams(this._def), - innerType: this, - defaultValue: defaultValueFunc, - typeName: ZodFirstPartyTypeKind.ZodDefault, - }); - } - brand() { - return new ZodBranded({ - typeName: ZodFirstPartyTypeKind.ZodBranded, - type: this, - ...processCreateParams(this._def), - }); - } - catch(def) { - const catchValueFunc = typeof def === "function" ? def : () => def; - return new ZodCatch({ - ...processCreateParams(this._def), - innerType: this, - catchValue: catchValueFunc, - typeName: ZodFirstPartyTypeKind.ZodCatch, - }); - } - describe(description) { - const This = this.constructor; - return new This({ - ...this._def, - description, - }); - } - pipe(target) { - return ZodPipeline.create(this, target); - } - readonly() { - return ZodReadonly.create(this); - } - isOptional() { - return this.safeParse(undefined).success; - } - isNullable() { - return this.safeParse(null).success; - } -} -const cuidRegex = /^c[^\s-]{8,}$/i; -const cuid2Regex = /^[0-9a-z]+$/; -const ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/i; -// const uuidRegex = -// /^([a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[a-f0-9]{4}-[a-f0-9]{12}|00000000-0000-0000-0000-000000000000)$/i; -const uuidRegex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i; -const nanoidRegex = /^[a-z0-9_-]{21}$/i; -const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/; -const durationRegex = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/; -// from https://stackoverflow.com/a/46181/1550155 -// old version: too slow, didn't support unicode -// const emailRegex = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; -//old email regex -// const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i; -// eslint-disable-next-line -// const emailRegex = -// /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\])|(\[IPv6:(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))\])|([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])*(\.[A-Za-z]{2,})+))$/; -// const emailRegex = -// /^[a-zA-Z0-9\.\!\#\$\%\&\'\*\+\/\=\?\^\_\`\{\|\}\~\-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; -// const emailRegex = -// /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i; -const emailRegex = /^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i; -// const emailRegex = -// /^[a-z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9\-]+)*$/i; -// from https://thekevinscott.com/emojis-in-javascript/#writing-a-regular-expression -const _emojiRegex = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; -let emojiRegex; -// faster, simpler, safer -const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; -const ipv4CidrRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/; -// const ipv6Regex = -// /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/; -const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/; -const ipv6CidrRegex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; -// https://stackoverflow.com/questions/7860392/determine-if-string-is-in-base64-using-javascript -const base64Regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/; -// https://base64.guru/standards/base64url -const base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/; -// simple -// const dateRegexSource = `\\d{4}-\\d{2}-\\d{2}`; -// no leap year validation -// const dateRegexSource = `\\d{4}-((0[13578]|10|12)-31|(0[13-9]|1[0-2])-30|(0[1-9]|1[0-2])-(0[1-9]|1\\d|2\\d))`; -// with leap year validation -const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`; -const dateRegex = new RegExp(`^${dateRegexSource}$`); -function timeRegexSource(args) { - let secondsRegexSource = `[0-5]\\d`; - if (args.precision) { - secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`; - } - else if (args.precision == null) { - secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`; - } - const secondsQuantifier = args.precision ? "+" : "?"; // require seconds if precision is nonzero - return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`; -} -function timeRegex(args) { - return new RegExp(`^${timeRegexSource(args)}$`); -} -// Adapted from https://stackoverflow.com/a/3143231 -function datetimeRegex(args) { - let regex = `${dateRegexSource}T${timeRegexSource(args)}`; - const opts = []; - opts.push(args.local ? `Z?` : `Z`); - if (args.offset) - opts.push(`([+-]\\d{2}:?\\d{2})`); - regex = `${regex}(${opts.join("|")})`; - return new RegExp(`^${regex}$`); -} -function isValidIP(ip, version) { - if ((version === "v4" || !version) && ipv4Regex.test(ip)) { - return true; - } - if ((version === "v6" || !version) && ipv6Regex.test(ip)) { - return true; - } - return false; -} -function types_isValidJWT(jwt, alg) { - if (!jwtRegex.test(jwt)) - return false; - try { - const [header] = jwt.split("."); - if (!header) - return false; - // Convert base64url to base64 - const base64 = header - .replace(/-/g, "+") - .replace(/_/g, "/") - .padEnd(header.length + ((4 - (header.length % 4)) % 4), "="); - // @ts-ignore - const decoded = JSON.parse(atob(base64)); - if (typeof decoded !== "object" || decoded === null) - return false; - if ("typ" in decoded && decoded?.typ !== "JWT") - return false; - if (!decoded.alg) - return false; - if (alg && decoded.alg !== alg) - return false; - return true; - } - catch { - return false; - } -} -function isValidCidr(ip, version) { - if ((version === "v4" || !version) && ipv4CidrRegex.test(ip)) { - return true; - } - if ((version === "v6" || !version) && ipv6CidrRegex.test(ip)) { - return true; - } - return false; -} -class ZodString extends ZodType { - _parse(input) { - if (this._def.coerce) { - input.data = String(input.data); - } - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.string) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.string, - received: ctx.parsedType, - }); - return INVALID; - } - const status = new ParseStatus(); - let ctx = undefined; - for (const check of this._def.checks) { - if (check.kind === "min") { - if (input.data.length < check.value) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.too_small, - minimum: check.value, - type: "string", - inclusive: true, - exact: false, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "max") { - if (input.data.length > check.value) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.too_big, - maximum: check.value, - type: "string", - inclusive: true, - exact: false, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "length") { - const tooBig = input.data.length > check.value; - const tooSmall = input.data.length < check.value; - if (tooBig || tooSmall) { - ctx = this._getOrReturnCtx(input, ctx); - if (tooBig) { - addIssueToContext(ctx, { - code: ZodIssueCode.too_big, - maximum: check.value, - type: "string", - inclusive: true, - exact: true, - message: check.message, - }); - } - else if (tooSmall) { - addIssueToContext(ctx, { - code: ZodIssueCode.too_small, - minimum: check.value, - type: "string", - inclusive: true, - exact: true, - message: check.message, - }); - } - status.dirty(); - } - } - else if (check.kind === "email") { - if (!emailRegex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "email", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "emoji") { - if (!emojiRegex) { - emojiRegex = new RegExp(_emojiRegex, "u"); - } - if (!emojiRegex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "emoji", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "uuid") { - if (!uuidRegex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "uuid", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "nanoid") { - if (!nanoidRegex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "nanoid", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "cuid") { - if (!cuidRegex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "cuid", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "cuid2") { - if (!cuid2Regex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "cuid2", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "ulid") { - if (!ulidRegex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "ulid", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "url") { - try { - // @ts-ignore - new URL(input.data); - } - catch { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "url", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "regex") { - check.regex.lastIndex = 0; - const testResult = check.regex.test(input.data); - if (!testResult) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "regex", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "trim") { - input.data = input.data.trim(); - } - else if (check.kind === "includes") { - if (!input.data.includes(check.value, check.position)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_string, - validation: { includes: check.value, position: check.position }, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "toLowerCase") { - input.data = input.data.toLowerCase(); - } - else if (check.kind === "toUpperCase") { - input.data = input.data.toUpperCase(); - } - else if (check.kind === "startsWith") { - if (!input.data.startsWith(check.value)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_string, - validation: { startsWith: check.value }, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "endsWith") { - if (!input.data.endsWith(check.value)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_string, - validation: { endsWith: check.value }, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "datetime") { - const regex = datetimeRegex(check); - if (!regex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_string, - validation: "datetime", - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "date") { - const regex = dateRegex; - if (!regex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_string, - validation: "date", - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "time") { - const regex = timeRegex(check); - if (!regex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_string, - validation: "time", - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "duration") { - if (!durationRegex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "duration", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "ip") { - if (!isValidIP(input.data, check.version)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "ip", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "jwt") { - if (!types_isValidJWT(input.data, check.alg)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "jwt", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "cidr") { - if (!isValidCidr(input.data, check.version)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "cidr", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "base64") { - if (!base64Regex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "base64", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "base64url") { - if (!base64urlRegex.test(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - validation: "base64url", - code: ZodIssueCode.invalid_string, - message: check.message, - }); - status.dirty(); - } - } - else { - util.assertNever(check); - } - } - return { status: status.value, value: input.data }; - } - _regex(regex, validation, message) { - return this.refinement((data) => regex.test(data), { - validation, - code: ZodIssueCode.invalid_string, - ...errorUtil.errToObj(message), - }); - } - _addCheck(check) { - return new ZodString({ - ...this._def, - checks: [...this._def.checks, check], - }); - } - email(message) { - return this._addCheck({ kind: "email", ...errorUtil.errToObj(message) }); - } - url(message) { - return this._addCheck({ kind: "url", ...errorUtil.errToObj(message) }); - } - emoji(message) { - return this._addCheck({ kind: "emoji", ...errorUtil.errToObj(message) }); - } - uuid(message) { - return this._addCheck({ kind: "uuid", ...errorUtil.errToObj(message) }); - } - nanoid(message) { - return this._addCheck({ kind: "nanoid", ...errorUtil.errToObj(message) }); - } - cuid(message) { - return this._addCheck({ kind: "cuid", ...errorUtil.errToObj(message) }); - } - cuid2(message) { - return this._addCheck({ kind: "cuid2", ...errorUtil.errToObj(message) }); - } - ulid(message) { - return this._addCheck({ kind: "ulid", ...errorUtil.errToObj(message) }); - } - base64(message) { - return this._addCheck({ kind: "base64", ...errorUtil.errToObj(message) }); - } - base64url(message) { - // base64url encoding is a modification of base64 that can safely be used in URLs and filenames - return this._addCheck({ - kind: "base64url", - ...errorUtil.errToObj(message), - }); - } - jwt(options) { - return this._addCheck({ kind: "jwt", ...errorUtil.errToObj(options) }); - } - ip(options) { - return this._addCheck({ kind: "ip", ...errorUtil.errToObj(options) }); - } - cidr(options) { - return this._addCheck({ kind: "cidr", ...errorUtil.errToObj(options) }); - } - datetime(options) { - if (typeof options === "string") { - return this._addCheck({ - kind: "datetime", - precision: null, - offset: false, - local: false, - message: options, - }); - } - return this._addCheck({ - kind: "datetime", - precision: typeof options?.precision === "undefined" ? null : options?.precision, - offset: options?.offset ?? false, - local: options?.local ?? false, - ...errorUtil.errToObj(options?.message), - }); - } - date(message) { - return this._addCheck({ kind: "date", message }); - } - time(options) { - if (typeof options === "string") { - return this._addCheck({ - kind: "time", - precision: null, - message: options, - }); - } - return this._addCheck({ - kind: "time", - precision: typeof options?.precision === "undefined" ? null : options?.precision, - ...errorUtil.errToObj(options?.message), - }); - } - duration(message) { - return this._addCheck({ kind: "duration", ...errorUtil.errToObj(message) }); - } - regex(regex, message) { - return this._addCheck({ - kind: "regex", - regex: regex, - ...errorUtil.errToObj(message), - }); - } - includes(value, options) { - return this._addCheck({ - kind: "includes", - value: value, - position: options?.position, - ...errorUtil.errToObj(options?.message), - }); - } - startsWith(value, message) { - return this._addCheck({ - kind: "startsWith", - value: value, - ...errorUtil.errToObj(message), - }); - } - endsWith(value, message) { - return this._addCheck({ - kind: "endsWith", - value: value, - ...errorUtil.errToObj(message), - }); - } - min(minLength, message) { - return this._addCheck({ - kind: "min", - value: minLength, - ...errorUtil.errToObj(message), - }); - } - max(maxLength, message) { - return this._addCheck({ - kind: "max", - value: maxLength, - ...errorUtil.errToObj(message), - }); - } - length(len, message) { - return this._addCheck({ - kind: "length", - value: len, - ...errorUtil.errToObj(message), - }); - } - /** - * Equivalent to `.min(1)` - */ - nonempty(message) { - return this.min(1, errorUtil.errToObj(message)); - } - trim() { - return new ZodString({ - ...this._def, - checks: [...this._def.checks, { kind: "trim" }], - }); - } - toLowerCase() { - return new ZodString({ - ...this._def, - checks: [...this._def.checks, { kind: "toLowerCase" }], - }); - } - toUpperCase() { - return new ZodString({ - ...this._def, - checks: [...this._def.checks, { kind: "toUpperCase" }], - }); - } - get isDatetime() { - return !!this._def.checks.find((ch) => ch.kind === "datetime"); - } - get isDate() { - return !!this._def.checks.find((ch) => ch.kind === "date"); - } - get isTime() { - return !!this._def.checks.find((ch) => ch.kind === "time"); - } - get isDuration() { - return !!this._def.checks.find((ch) => ch.kind === "duration"); - } - get isEmail() { - return !!this._def.checks.find((ch) => ch.kind === "email"); - } - get isURL() { - return !!this._def.checks.find((ch) => ch.kind === "url"); - } - get isEmoji() { - return !!this._def.checks.find((ch) => ch.kind === "emoji"); - } - get isUUID() { - return !!this._def.checks.find((ch) => ch.kind === "uuid"); - } - get isNANOID() { - return !!this._def.checks.find((ch) => ch.kind === "nanoid"); - } - get isCUID() { - return !!this._def.checks.find((ch) => ch.kind === "cuid"); - } - get isCUID2() { - return !!this._def.checks.find((ch) => ch.kind === "cuid2"); - } - get isULID() { - return !!this._def.checks.find((ch) => ch.kind === "ulid"); - } - get isIP() { - return !!this._def.checks.find((ch) => ch.kind === "ip"); - } - get isCIDR() { - return !!this._def.checks.find((ch) => ch.kind === "cidr"); - } - get isBase64() { - return !!this._def.checks.find((ch) => ch.kind === "base64"); - } - get isBase64url() { - // base64url encoding is a modification of base64 that can safely be used in URLs and filenames - return !!this._def.checks.find((ch) => ch.kind === "base64url"); - } - get minLength() { - let min = null; - for (const ch of this._def.checks) { - if (ch.kind === "min") { - if (min === null || ch.value > min) - min = ch.value; - } - } - return min; - } - get maxLength() { - let max = null; - for (const ch of this._def.checks) { - if (ch.kind === "max") { - if (max === null || ch.value < max) - max = ch.value; - } - } - return max; - } -} -ZodString.create = (params) => { - return new ZodString({ - checks: [], - typeName: ZodFirstPartyTypeKind.ZodString, - coerce: params?.coerce ?? false, - ...processCreateParams(params), - }); -}; -// https://stackoverflow.com/questions/3966484/why-does-modulus-operator-return-fractional-number-in-javascript/31711034#31711034 -function types_floatSafeRemainder(val, step) { - const valDecCount = (val.toString().split(".")[1] || "").length; - const stepDecCount = (step.toString().split(".")[1] || "").length; - const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount; - const valInt = Number.parseInt(val.toFixed(decCount).replace(".", "")); - const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", "")); - return (valInt % stepInt) / 10 ** decCount; -} -class ZodNumber extends ZodType { - constructor() { - super(...arguments); - this.min = this.gte; - this.max = this.lte; - this.step = this.multipleOf; - } - _parse(input) { - if (this._def.coerce) { - input.data = Number(input.data); - } - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.number) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.number, - received: ctx.parsedType, - }); - return INVALID; - } - let ctx = undefined; - const status = new ParseStatus(); - for (const check of this._def.checks) { - if (check.kind === "int") { - if (!util.isInteger(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: "integer", - received: "float", - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "min") { - const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value; - if (tooSmall) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.too_small, - minimum: check.value, - type: "number", - inclusive: check.inclusive, - exact: false, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "max") { - const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value; - if (tooBig) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.too_big, - maximum: check.value, - type: "number", - inclusive: check.inclusive, - exact: false, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "multipleOf") { - if (types_floatSafeRemainder(input.data, check.value) !== 0) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.not_multiple_of, - multipleOf: check.value, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "finite") { - if (!Number.isFinite(input.data)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.not_finite, - message: check.message, - }); - status.dirty(); - } - } - else { - util.assertNever(check); - } - } - return { status: status.value, value: input.data }; - } - gte(value, message) { - return this.setLimit("min", value, true, errorUtil.toString(message)); - } - gt(value, message) { - return this.setLimit("min", value, false, errorUtil.toString(message)); - } - lte(value, message) { - return this.setLimit("max", value, true, errorUtil.toString(message)); - } - lt(value, message) { - return this.setLimit("max", value, false, errorUtil.toString(message)); - } - setLimit(kind, value, inclusive, message) { - return new ZodNumber({ - ...this._def, - checks: [ - ...this._def.checks, - { - kind, - value, - inclusive, - message: errorUtil.toString(message), - }, - ], - }); - } - _addCheck(check) { - return new ZodNumber({ - ...this._def, - checks: [...this._def.checks, check], - }); - } - int(message) { - return this._addCheck({ - kind: "int", - message: errorUtil.toString(message), - }); - } - positive(message) { - return this._addCheck({ - kind: "min", - value: 0, - inclusive: false, - message: errorUtil.toString(message), - }); - } - negative(message) { - return this._addCheck({ - kind: "max", - value: 0, - inclusive: false, - message: errorUtil.toString(message), - }); - } - nonpositive(message) { - return this._addCheck({ - kind: "max", - value: 0, - inclusive: true, - message: errorUtil.toString(message), - }); - } - nonnegative(message) { - return this._addCheck({ - kind: "min", - value: 0, - inclusive: true, - message: errorUtil.toString(message), - }); - } - multipleOf(value, message) { - return this._addCheck({ - kind: "multipleOf", - value: value, - message: errorUtil.toString(message), - }); - } - finite(message) { - return this._addCheck({ - kind: "finite", - message: errorUtil.toString(message), - }); - } - safe(message) { - return this._addCheck({ - kind: "min", - inclusive: true, - value: Number.MIN_SAFE_INTEGER, - message: errorUtil.toString(message), - })._addCheck({ - kind: "max", - inclusive: true, - value: Number.MAX_SAFE_INTEGER, - message: errorUtil.toString(message), - }); - } - get minValue() { - let min = null; - for (const ch of this._def.checks) { - if (ch.kind === "min") { - if (min === null || ch.value > min) - min = ch.value; - } - } - return min; - } - get maxValue() { - let max = null; - for (const ch of this._def.checks) { - if (ch.kind === "max") { - if (max === null || ch.value < max) - max = ch.value; - } - } - return max; - } - get isInt() { - return !!this._def.checks.find((ch) => ch.kind === "int" || (ch.kind === "multipleOf" && util.isInteger(ch.value))); - } - get isFinite() { - let max = null; - let min = null; - for (const ch of this._def.checks) { - if (ch.kind === "finite" || ch.kind === "int" || ch.kind === "multipleOf") { - return true; - } - else if (ch.kind === "min") { - if (min === null || ch.value > min) - min = ch.value; - } - else if (ch.kind === "max") { - if (max === null || ch.value < max) - max = ch.value; - } - } - return Number.isFinite(min) && Number.isFinite(max); - } -} -ZodNumber.create = (params) => { - return new ZodNumber({ - checks: [], - typeName: ZodFirstPartyTypeKind.ZodNumber, - coerce: params?.coerce || false, - ...processCreateParams(params), - }); -}; -class ZodBigInt extends ZodType { - constructor() { - super(...arguments); - this.min = this.gte; - this.max = this.lte; - } - _parse(input) { - if (this._def.coerce) { - try { - input.data = BigInt(input.data); - } - catch { - return this._getInvalidInput(input); - } - } - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.bigint) { - return this._getInvalidInput(input); - } - let ctx = undefined; - const status = new ParseStatus(); - for (const check of this._def.checks) { - if (check.kind === "min") { - const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value; - if (tooSmall) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.too_small, - type: "bigint", - minimum: check.value, - inclusive: check.inclusive, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "max") { - const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value; - if (tooBig) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.too_big, - type: "bigint", - maximum: check.value, - inclusive: check.inclusive, - message: check.message, - }); - status.dirty(); - } - } - else if (check.kind === "multipleOf") { - if (input.data % check.value !== BigInt(0)) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.not_multiple_of, - multipleOf: check.value, - message: check.message, - }); - status.dirty(); - } - } - else { - util.assertNever(check); - } - } - return { status: status.value, value: input.data }; - } - _getInvalidInput(input) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.bigint, - received: ctx.parsedType, - }); - return INVALID; - } - gte(value, message) { - return this.setLimit("min", value, true, errorUtil.toString(message)); - } - gt(value, message) { - return this.setLimit("min", value, false, errorUtil.toString(message)); - } - lte(value, message) { - return this.setLimit("max", value, true, errorUtil.toString(message)); - } - lt(value, message) { - return this.setLimit("max", value, false, errorUtil.toString(message)); - } - setLimit(kind, value, inclusive, message) { - return new ZodBigInt({ - ...this._def, - checks: [ - ...this._def.checks, - { - kind, - value, - inclusive, - message: errorUtil.toString(message), - }, - ], - }); - } - _addCheck(check) { - return new ZodBigInt({ - ...this._def, - checks: [...this._def.checks, check], - }); - } - positive(message) { - return this._addCheck({ - kind: "min", - value: BigInt(0), - inclusive: false, - message: errorUtil.toString(message), - }); - } - negative(message) { - return this._addCheck({ - kind: "max", - value: BigInt(0), - inclusive: false, - message: errorUtil.toString(message), - }); - } - nonpositive(message) { - return this._addCheck({ - kind: "max", - value: BigInt(0), - inclusive: true, - message: errorUtil.toString(message), - }); - } - nonnegative(message) { - return this._addCheck({ - kind: "min", - value: BigInt(0), - inclusive: true, - message: errorUtil.toString(message), - }); - } - multipleOf(value, message) { - return this._addCheck({ - kind: "multipleOf", - value, - message: errorUtil.toString(message), - }); - } - get minValue() { - let min = null; - for (const ch of this._def.checks) { - if (ch.kind === "min") { - if (min === null || ch.value > min) - min = ch.value; - } - } - return min; - } - get maxValue() { - let max = null; - for (const ch of this._def.checks) { - if (ch.kind === "max") { - if (max === null || ch.value < max) - max = ch.value; - } - } - return max; - } -} -ZodBigInt.create = (params) => { - return new ZodBigInt({ - checks: [], - typeName: ZodFirstPartyTypeKind.ZodBigInt, - coerce: params?.coerce ?? false, - ...processCreateParams(params), - }); -}; -class ZodBoolean extends ZodType { - _parse(input) { - if (this._def.coerce) { - input.data = Boolean(input.data); - } - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.boolean) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.boolean, - received: ctx.parsedType, - }); - return INVALID; - } - return OK(input.data); - } -} -ZodBoolean.create = (params) => { - return new ZodBoolean({ - typeName: ZodFirstPartyTypeKind.ZodBoolean, - coerce: params?.coerce || false, - ...processCreateParams(params), - }); -}; -class ZodDate extends ZodType { - _parse(input) { - if (this._def.coerce) { - input.data = new Date(input.data); - } - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.date) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.date, - received: ctx.parsedType, - }); - return INVALID; - } - if (Number.isNaN(input.data.getTime())) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_date, - }); - return INVALID; - } - const status = new ParseStatus(); - let ctx = undefined; - for (const check of this._def.checks) { - if (check.kind === "min") { - if (input.data.getTime() < check.value) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.too_small, - message: check.message, - inclusive: true, - exact: false, - minimum: check.value, - type: "date", - }); - status.dirty(); - } - } - else if (check.kind === "max") { - if (input.data.getTime() > check.value) { - ctx = this._getOrReturnCtx(input, ctx); - addIssueToContext(ctx, { - code: ZodIssueCode.too_big, - message: check.message, - inclusive: true, - exact: false, - maximum: check.value, - type: "date", - }); - status.dirty(); - } - } - else { - util.assertNever(check); - } - } - return { - status: status.value, - value: new Date(input.data.getTime()), - }; - } - _addCheck(check) { - return new ZodDate({ - ...this._def, - checks: [...this._def.checks, check], - }); - } - min(minDate, message) { - return this._addCheck({ - kind: "min", - value: minDate.getTime(), - message: errorUtil.toString(message), - }); - } - max(maxDate, message) { - return this._addCheck({ - kind: "max", - value: maxDate.getTime(), - message: errorUtil.toString(message), - }); - } - get minDate() { - let min = null; - for (const ch of this._def.checks) { - if (ch.kind === "min") { - if (min === null || ch.value > min) - min = ch.value; - } - } - return min != null ? new Date(min) : null; - } - get maxDate() { - let max = null; - for (const ch of this._def.checks) { - if (ch.kind === "max") { - if (max === null || ch.value < max) - max = ch.value; - } - } - return max != null ? new Date(max) : null; - } -} -ZodDate.create = (params) => { - return new ZodDate({ - checks: [], - coerce: params?.coerce || false, - typeName: ZodFirstPartyTypeKind.ZodDate, - ...processCreateParams(params), - }); -}; -class ZodSymbol extends ZodType { - _parse(input) { - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.symbol) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.symbol, - received: ctx.parsedType, - }); - return INVALID; - } - return OK(input.data); - } -} -ZodSymbol.create = (params) => { - return new ZodSymbol({ - typeName: ZodFirstPartyTypeKind.ZodSymbol, - ...processCreateParams(params), - }); -}; -class ZodUndefined extends ZodType { - _parse(input) { - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.undefined) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.undefined, - received: ctx.parsedType, - }); - return INVALID; - } - return OK(input.data); - } -} -ZodUndefined.create = (params) => { - return new ZodUndefined({ - typeName: ZodFirstPartyTypeKind.ZodUndefined, - ...processCreateParams(params), - }); -}; -class ZodNull extends ZodType { - _parse(input) { - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.null) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.null, - received: ctx.parsedType, - }); - return INVALID; - } - return OK(input.data); - } -} -ZodNull.create = (params) => { - return new ZodNull({ - typeName: ZodFirstPartyTypeKind.ZodNull, - ...processCreateParams(params), - }); -}; -class ZodAny extends ZodType { - constructor() { - super(...arguments); - // to prevent instances of other classes from extending ZodAny. this causes issues with catchall in ZodObject. - this._any = true; - } - _parse(input) { - return OK(input.data); - } -} -ZodAny.create = (params) => { - return new ZodAny({ - typeName: ZodFirstPartyTypeKind.ZodAny, - ...processCreateParams(params), - }); -}; -class ZodUnknown extends ZodType { - constructor() { - super(...arguments); - // required - this._unknown = true; - } - _parse(input) { - return OK(input.data); - } -} -ZodUnknown.create = (params) => { - return new ZodUnknown({ - typeName: ZodFirstPartyTypeKind.ZodUnknown, - ...processCreateParams(params), - }); -}; -class ZodNever extends ZodType { - _parse(input) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.never, - received: ctx.parsedType, - }); - return INVALID; - } -} -ZodNever.create = (params) => { - return new ZodNever({ - typeName: ZodFirstPartyTypeKind.ZodNever, - ...processCreateParams(params), - }); -}; -class ZodVoid extends ZodType { - _parse(input) { - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.undefined) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.void, - received: ctx.parsedType, - }); - return INVALID; - } - return OK(input.data); - } -} -ZodVoid.create = (params) => { - return new ZodVoid({ - typeName: ZodFirstPartyTypeKind.ZodVoid, - ...processCreateParams(params), - }); -}; -class ZodArray extends ZodType { - _parse(input) { - const { ctx, status } = this._processInputParams(input); - const def = this._def; - if (ctx.parsedType !== ZodParsedType.array) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.array, - received: ctx.parsedType, - }); - return INVALID; - } - if (def.exactLength !== null) { - const tooBig = ctx.data.length > def.exactLength.value; - const tooSmall = ctx.data.length < def.exactLength.value; - if (tooBig || tooSmall) { - addIssueToContext(ctx, { - code: tooBig ? ZodIssueCode.too_big : ZodIssueCode.too_small, - minimum: (tooSmall ? def.exactLength.value : undefined), - maximum: (tooBig ? def.exactLength.value : undefined), - type: "array", - inclusive: true, - exact: true, - message: def.exactLength.message, - }); - status.dirty(); - } - } - if (def.minLength !== null) { - if (ctx.data.length < def.minLength.value) { - addIssueToContext(ctx, { - code: ZodIssueCode.too_small, - minimum: def.minLength.value, - type: "array", - inclusive: true, - exact: false, - message: def.minLength.message, - }); - status.dirty(); - } - } - if (def.maxLength !== null) { - if (ctx.data.length > def.maxLength.value) { - addIssueToContext(ctx, { - code: ZodIssueCode.too_big, - maximum: def.maxLength.value, - type: "array", - inclusive: true, - exact: false, - message: def.maxLength.message, - }); - status.dirty(); - } - } - if (ctx.common.async) { - return Promise.all([...ctx.data].map((item, i) => { - return def.type._parseAsync(new ParseInputLazyPath(ctx, item, ctx.path, i)); - })).then((result) => { - return ParseStatus.mergeArray(status, result); - }); - } - const result = [...ctx.data].map((item, i) => { - return def.type._parseSync(new ParseInputLazyPath(ctx, item, ctx.path, i)); - }); - return ParseStatus.mergeArray(status, result); - } - get element() { - return this._def.type; - } - min(minLength, message) { - return new ZodArray({ - ...this._def, - minLength: { value: minLength, message: errorUtil.toString(message) }, - }); - } - max(maxLength, message) { - return new ZodArray({ - ...this._def, - maxLength: { value: maxLength, message: errorUtil.toString(message) }, - }); - } - length(len, message) { - return new ZodArray({ - ...this._def, - exactLength: { value: len, message: errorUtil.toString(message) }, - }); - } - nonempty(message) { - return this.min(1, message); - } -} -ZodArray.create = (schema, params) => { - return new ZodArray({ - type: schema, - minLength: null, - maxLength: null, - exactLength: null, - typeName: ZodFirstPartyTypeKind.ZodArray, - ...processCreateParams(params), - }); -}; -function deepPartialify(schema) { - if (schema instanceof ZodObject) { - const newShape = {}; - for (const key in schema.shape) { - const fieldSchema = schema.shape[key]; - newShape[key] = ZodOptional.create(deepPartialify(fieldSchema)); - } - return new ZodObject({ - ...schema._def, - shape: () => newShape, - }); - } - else if (schema instanceof ZodArray) { - return new ZodArray({ - ...schema._def, - type: deepPartialify(schema.element), - }); - } - else if (schema instanceof ZodOptional) { - return ZodOptional.create(deepPartialify(schema.unwrap())); - } - else if (schema instanceof ZodNullable) { - return ZodNullable.create(deepPartialify(schema.unwrap())); - } - else if (schema instanceof ZodTuple) { - return ZodTuple.create(schema.items.map((item) => deepPartialify(item))); - } - else { - return schema; - } -} -class ZodObject extends ZodType { - constructor() { - super(...arguments); - this._cached = null; - /** - * @deprecated In most cases, this is no longer needed - unknown properties are now silently stripped. - * If you want to pass through unknown properties, use `.passthrough()` instead. - */ - this.nonstrict = this.passthrough; - // extend< - // Augmentation extends ZodRawShape, - // NewOutput extends util.flatten<{ - // [k in keyof Augmentation | keyof Output]: k extends keyof Augmentation - // ? Augmentation[k]["_output"] - // : k extends keyof Output - // ? Output[k] - // : never; - // }>, - // NewInput extends util.flatten<{ - // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation - // ? Augmentation[k]["_input"] - // : k extends keyof Input - // ? Input[k] - // : never; - // }> - // >( - // augmentation: Augmentation - // ): ZodObject< - // extendShape, - // UnknownKeys, - // Catchall, - // NewOutput, - // NewInput - // > { - // return new ZodObject({ - // ...this._def, - // shape: () => ({ - // ...this._def.shape(), - // ...augmentation, - // }), - // }) as any; - // } - /** - * @deprecated Use `.extend` instead - * */ - this.augment = this.extend; - } - _getCached() { - if (this._cached !== null) - return this._cached; - const shape = this._def.shape(); - const keys = util.objectKeys(shape); - this._cached = { shape, keys }; - return this._cached; - } - _parse(input) { - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.object) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.object, - received: ctx.parsedType, - }); - return INVALID; - } - const { status, ctx } = this._processInputParams(input); - const { shape, keys: shapeKeys } = this._getCached(); - const extraKeys = []; - if (!(this._def.catchall instanceof ZodNever && this._def.unknownKeys === "strip")) { - for (const key in ctx.data) { - if (!shapeKeys.includes(key)) { - extraKeys.push(key); - } - } - } - const pairs = []; - for (const key of shapeKeys) { - const keyValidator = shape[key]; - const value = ctx.data[key]; - pairs.push({ - key: { status: "valid", value: key }, - value: keyValidator._parse(new ParseInputLazyPath(ctx, value, ctx.path, key)), - alwaysSet: key in ctx.data, - }); - } - if (this._def.catchall instanceof ZodNever) { - const unknownKeys = this._def.unknownKeys; - if (unknownKeys === "passthrough") { - for (const key of extraKeys) { - pairs.push({ - key: { status: "valid", value: key }, - value: { status: "valid", value: ctx.data[key] }, - }); - } - } - else if (unknownKeys === "strict") { - if (extraKeys.length > 0) { - addIssueToContext(ctx, { - code: ZodIssueCode.unrecognized_keys, - keys: extraKeys, - }); - status.dirty(); - } - } - else if (unknownKeys === "strip") { - } - else { - throw new Error(`Internal ZodObject error: invalid unknownKeys value.`); - } - } - else { - // run catchall validation - const catchall = this._def.catchall; - for (const key of extraKeys) { - const value = ctx.data[key]; - pairs.push({ - key: { status: "valid", value: key }, - value: catchall._parse(new ParseInputLazyPath(ctx, value, ctx.path, key) //, ctx.child(key), value, getParsedType(value) - ), - alwaysSet: key in ctx.data, - }); - } - } - if (ctx.common.async) { - return Promise.resolve() - .then(async () => { - const syncPairs = []; - for (const pair of pairs) { - const key = await pair.key; - const value = await pair.value; - syncPairs.push({ - key, - value, - alwaysSet: pair.alwaysSet, - }); - } - return syncPairs; - }) - .then((syncPairs) => { - return ParseStatus.mergeObjectSync(status, syncPairs); - }); - } - else { - return ParseStatus.mergeObjectSync(status, pairs); - } - } - get shape() { - return this._def.shape(); - } - strict(message) { - errorUtil.errToObj; - return new ZodObject({ - ...this._def, - unknownKeys: "strict", - ...(message !== undefined - ? { - errorMap: (issue, ctx) => { - const defaultError = this._def.errorMap?.(issue, ctx).message ?? ctx.defaultError; - if (issue.code === "unrecognized_keys") - return { - message: errorUtil.errToObj(message).message ?? defaultError, - }; - return { - message: defaultError, - }; - }, - } - : {}), - }); - } - strip() { - return new ZodObject({ - ...this._def, - unknownKeys: "strip", - }); - } - passthrough() { - return new ZodObject({ - ...this._def, - unknownKeys: "passthrough", - }); - } - // const AugmentFactory = - // (def: Def) => - // ( - // augmentation: Augmentation - // ): ZodObject< - // extendShape, Augmentation>, - // Def["unknownKeys"], - // Def["catchall"] - // > => { - // return new ZodObject({ - // ...def, - // shape: () => ({ - // ...def.shape(), - // ...augmentation, - // }), - // }) as any; - // }; - extend(augmentation) { - return new ZodObject({ - ...this._def, - shape: () => ({ - ...this._def.shape(), - ...augmentation, - }), - }); - } - /** - * Prior to zod@1.0.12 there was a bug in the - * inferred type of merged objects. Please - * upgrade if you are experiencing issues. - */ - merge(merging) { - const merged = new ZodObject({ - unknownKeys: merging._def.unknownKeys, - catchall: merging._def.catchall, - shape: () => ({ - ...this._def.shape(), - ...merging._def.shape(), - }), - typeName: ZodFirstPartyTypeKind.ZodObject, - }); - return merged; - } - // merge< - // Incoming extends AnyZodObject, - // Augmentation extends Incoming["shape"], - // NewOutput extends { - // [k in keyof Augmentation | keyof Output]: k extends keyof Augmentation - // ? Augmentation[k]["_output"] - // : k extends keyof Output - // ? Output[k] - // : never; - // }, - // NewInput extends { - // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation - // ? Augmentation[k]["_input"] - // : k extends keyof Input - // ? Input[k] - // : never; - // } - // >( - // merging: Incoming - // ): ZodObject< - // extendShape>, - // Incoming["_def"]["unknownKeys"], - // Incoming["_def"]["catchall"], - // NewOutput, - // NewInput - // > { - // const merged: any = new ZodObject({ - // unknownKeys: merging._def.unknownKeys, - // catchall: merging._def.catchall, - // shape: () => - // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), - // typeName: ZodFirstPartyTypeKind.ZodObject, - // }) as any; - // return merged; - // } - setKey(key, schema) { - return this.augment({ [key]: schema }); - } - // merge( - // merging: Incoming - // ): //ZodObject = (merging) => { - // ZodObject< - // extendShape>, - // Incoming["_def"]["unknownKeys"], - // Incoming["_def"]["catchall"] - // > { - // // const mergedShape = objectUtil.mergeShapes( - // // this._def.shape(), - // // merging._def.shape() - // // ); - // const merged: any = new ZodObject({ - // unknownKeys: merging._def.unknownKeys, - // catchall: merging._def.catchall, - // shape: () => - // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), - // typeName: ZodFirstPartyTypeKind.ZodObject, - // }) as any; - // return merged; - // } - catchall(index) { - return new ZodObject({ - ...this._def, - catchall: index, - }); - } - pick(mask) { - const shape = {}; - for (const key of util.objectKeys(mask)) { - if (mask[key] && this.shape[key]) { - shape[key] = this.shape[key]; - } - } - return new ZodObject({ - ...this._def, - shape: () => shape, - }); - } - omit(mask) { - const shape = {}; - for (const key of util.objectKeys(this.shape)) { - if (!mask[key]) { - shape[key] = this.shape[key]; - } - } - return new ZodObject({ - ...this._def, - shape: () => shape, - }); - } - /** - * @deprecated - */ - deepPartial() { - return deepPartialify(this); - } - partial(mask) { - const newShape = {}; - for (const key of util.objectKeys(this.shape)) { - const fieldSchema = this.shape[key]; - if (mask && !mask[key]) { - newShape[key] = fieldSchema; - } - else { - newShape[key] = fieldSchema.optional(); - } - } - return new ZodObject({ - ...this._def, - shape: () => newShape, - }); - } - required(mask) { - const newShape = {}; - for (const key of util.objectKeys(this.shape)) { - if (mask && !mask[key]) { - newShape[key] = this.shape[key]; - } - else { - const fieldSchema = this.shape[key]; - let newField = fieldSchema; - while (newField instanceof ZodOptional) { - newField = newField._def.innerType; - } - newShape[key] = newField; - } - } - return new ZodObject({ - ...this._def, - shape: () => newShape, - }); - } - keyof() { - return createZodEnum(util.objectKeys(this.shape)); - } -} -ZodObject.create = (shape, params) => { - return new ZodObject({ - shape: () => shape, - unknownKeys: "strip", - catchall: ZodNever.create(), - typeName: ZodFirstPartyTypeKind.ZodObject, - ...processCreateParams(params), - }); -}; -ZodObject.strictCreate = (shape, params) => { - return new ZodObject({ - shape: () => shape, - unknownKeys: "strict", - catchall: ZodNever.create(), - typeName: ZodFirstPartyTypeKind.ZodObject, - ...processCreateParams(params), - }); -}; -ZodObject.lazycreate = (shape, params) => { - return new ZodObject({ - shape, - unknownKeys: "strip", - catchall: ZodNever.create(), - typeName: ZodFirstPartyTypeKind.ZodObject, - ...processCreateParams(params), - }); -}; -class ZodUnion extends ZodType { - _parse(input) { - const { ctx } = this._processInputParams(input); - const options = this._def.options; - function handleResults(results) { - // return first issue-free validation if it exists - for (const result of results) { - if (result.result.status === "valid") { - return result.result; - } - } - for (const result of results) { - if (result.result.status === "dirty") { - // add issues from dirty option - ctx.common.issues.push(...result.ctx.common.issues); - return result.result; - } - } - // return invalid - const unionErrors = results.map((result) => new ZodError(result.ctx.common.issues)); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_union, - unionErrors, - }); - return INVALID; - } - if (ctx.common.async) { - return Promise.all(options.map(async (option) => { - const childCtx = { - ...ctx, - common: { - ...ctx.common, - issues: [], - }, - parent: null, - }; - return { - result: await option._parseAsync({ - data: ctx.data, - path: ctx.path, - parent: childCtx, - }), - ctx: childCtx, - }; - })).then(handleResults); - } - else { - let dirty = undefined; - const issues = []; - for (const option of options) { - const childCtx = { - ...ctx, - common: { - ...ctx.common, - issues: [], - }, - parent: null, - }; - const result = option._parseSync({ - data: ctx.data, - path: ctx.path, - parent: childCtx, - }); - if (result.status === "valid") { - return result; - } - else if (result.status === "dirty" && !dirty) { - dirty = { result, ctx: childCtx }; - } - if (childCtx.common.issues.length) { - issues.push(childCtx.common.issues); - } - } - if (dirty) { - ctx.common.issues.push(...dirty.ctx.common.issues); - return dirty.result; - } - const unionErrors = issues.map((issues) => new ZodError(issues)); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_union, - unionErrors, - }); - return INVALID; - } - } - get options() { - return this._def.options; - } -} -ZodUnion.create = (types, params) => { - return new ZodUnion({ - options: types, - typeName: ZodFirstPartyTypeKind.ZodUnion, - ...processCreateParams(params), - }); -}; -///////////////////////////////////////////////////// -///////////////////////////////////////////////////// -////////// ////////// -////////// ZodDiscriminatedUnion ////////// -////////// ////////// -///////////////////////////////////////////////////// -///////////////////////////////////////////////////// -const getDiscriminator = (type) => { - if (type instanceof ZodLazy) { - return getDiscriminator(type.schema); - } - else if (type instanceof ZodEffects) { - return getDiscriminator(type.innerType()); - } - else if (type instanceof ZodLiteral) { - return [type.value]; - } - else if (type instanceof ZodEnum) { - return type.options; - } - else if (type instanceof ZodNativeEnum) { - // eslint-disable-next-line ban/ban - return util.objectValues(type.enum); - } - else if (type instanceof ZodDefault) { - return getDiscriminator(type._def.innerType); - } - else if (type instanceof ZodUndefined) { - return [undefined]; - } - else if (type instanceof ZodNull) { - return [null]; - } - else if (type instanceof ZodOptional) { - return [undefined, ...getDiscriminator(type.unwrap())]; - } - else if (type instanceof ZodNullable) { - return [null, ...getDiscriminator(type.unwrap())]; - } - else if (type instanceof ZodBranded) { - return getDiscriminator(type.unwrap()); - } - else if (type instanceof ZodReadonly) { - return getDiscriminator(type.unwrap()); - } - else if (type instanceof ZodCatch) { - return getDiscriminator(type._def.innerType); - } - else { - return []; - } -}; -class ZodDiscriminatedUnion extends ZodType { - _parse(input) { - const { ctx } = this._processInputParams(input); - if (ctx.parsedType !== ZodParsedType.object) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.object, - received: ctx.parsedType, - }); - return INVALID; - } - const discriminator = this.discriminator; - const discriminatorValue = ctx.data[discriminator]; - const option = this.optionsMap.get(discriminatorValue); - if (!option) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_union_discriminator, - options: Array.from(this.optionsMap.keys()), - path: [discriminator], - }); - return INVALID; - } - if (ctx.common.async) { - return option._parseAsync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - }); - } - else { - return option._parseSync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - }); - } - } - get discriminator() { - return this._def.discriminator; - } - get options() { - return this._def.options; - } - get optionsMap() { - return this._def.optionsMap; - } - /** - * The constructor of the discriminated union schema. Its behaviour is very similar to that of the normal z.union() constructor. - * However, it only allows a union of objects, all of which need to share a discriminator property. This property must - * have a different value for each object in the union. - * @param discriminator the name of the discriminator property - * @param types an array of object schemas - * @param params - */ - static create(discriminator, options, params) { - // Get all the valid discriminator values - const optionsMap = new Map(); - // try { - for (const type of options) { - const discriminatorValues = getDiscriminator(type.shape[discriminator]); - if (!discriminatorValues.length) { - throw new Error(`A discriminator value for key \`${discriminator}\` could not be extracted from all schema options`); - } - for (const value of discriminatorValues) { - if (optionsMap.has(value)) { - throw new Error(`Discriminator property ${String(discriminator)} has duplicate value ${String(value)}`); - } - optionsMap.set(value, type); - } - } - return new ZodDiscriminatedUnion({ - typeName: ZodFirstPartyTypeKind.ZodDiscriminatedUnion, - discriminator, - options, - optionsMap, - ...processCreateParams(params), - }); - } -} -function types_mergeValues(a, b) { - const aType = util_getParsedType(a); - const bType = util_getParsedType(b); - if (a === b) { - return { valid: true, data: a }; - } - else if (aType === ZodParsedType.object && bType === ZodParsedType.object) { - const bKeys = util.objectKeys(b); - const sharedKeys = util.objectKeys(a).filter((key) => bKeys.indexOf(key) !== -1); - const newObj = { ...a, ...b }; - for (const key of sharedKeys) { - const sharedValue = types_mergeValues(a[key], b[key]); - if (!sharedValue.valid) { - return { valid: false }; - } - newObj[key] = sharedValue.data; - } - return { valid: true, data: newObj }; - } - else if (aType === ZodParsedType.array && bType === ZodParsedType.array) { - if (a.length !== b.length) { - return { valid: false }; - } - const newArray = []; - for (let index = 0; index < a.length; index++) { - const itemA = a[index]; - const itemB = b[index]; - const sharedValue = types_mergeValues(itemA, itemB); - if (!sharedValue.valid) { - return { valid: false }; - } - newArray.push(sharedValue.data); - } - return { valid: true, data: newArray }; - } - else if (aType === ZodParsedType.date && bType === ZodParsedType.date && +a === +b) { - return { valid: true, data: a }; - } - else { - return { valid: false }; - } -} -class ZodIntersection extends ZodType { - _parse(input) { - const { status, ctx } = this._processInputParams(input); - const handleParsed = (parsedLeft, parsedRight) => { - if (isAborted(parsedLeft) || isAborted(parsedRight)) { - return INVALID; - } - const merged = types_mergeValues(parsedLeft.value, parsedRight.value); - if (!merged.valid) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_intersection_types, - }); - return INVALID; - } - if (isDirty(parsedLeft) || isDirty(parsedRight)) { - status.dirty(); - } - return { status: status.value, value: merged.data }; - }; - if (ctx.common.async) { - return Promise.all([ - this._def.left._parseAsync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - }), - this._def.right._parseAsync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - }), - ]).then(([left, right]) => handleParsed(left, right)); - } - else { - return handleParsed(this._def.left._parseSync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - }), this._def.right._parseSync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - })); - } - } -} -ZodIntersection.create = (left, right, params) => { - return new ZodIntersection({ - left: left, - right: right, - typeName: ZodFirstPartyTypeKind.ZodIntersection, - ...processCreateParams(params), - }); -}; -// type ZodTupleItems = [ZodTypeAny, ...ZodTypeAny[]]; -class ZodTuple extends ZodType { - _parse(input) { - const { status, ctx } = this._processInputParams(input); - if (ctx.parsedType !== ZodParsedType.array) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.array, - received: ctx.parsedType, - }); - return INVALID; - } - if (ctx.data.length < this._def.items.length) { - addIssueToContext(ctx, { - code: ZodIssueCode.too_small, - minimum: this._def.items.length, - inclusive: true, - exact: false, - type: "array", - }); - return INVALID; - } - const rest = this._def.rest; - if (!rest && ctx.data.length > this._def.items.length) { - addIssueToContext(ctx, { - code: ZodIssueCode.too_big, - maximum: this._def.items.length, - inclusive: true, - exact: false, - type: "array", - }); - status.dirty(); - } - const items = [...ctx.data] - .map((item, itemIndex) => { - const schema = this._def.items[itemIndex] || this._def.rest; - if (!schema) - return null; - return schema._parse(new ParseInputLazyPath(ctx, item, ctx.path, itemIndex)); - }) - .filter((x) => !!x); // filter nulls - if (ctx.common.async) { - return Promise.all(items).then((results) => { - return ParseStatus.mergeArray(status, results); - }); - } - else { - return ParseStatus.mergeArray(status, items); - } - } - get items() { - return this._def.items; - } - rest(rest) { - return new ZodTuple({ - ...this._def, - rest, - }); - } -} -ZodTuple.create = (schemas, params) => { - if (!Array.isArray(schemas)) { - throw new Error("You must pass an array of schemas to z.tuple([ ... ])"); - } - return new ZodTuple({ - items: schemas, - typeName: ZodFirstPartyTypeKind.ZodTuple, - rest: null, - ...processCreateParams(params), - }); -}; -class ZodRecord extends ZodType { - get keySchema() { - return this._def.keyType; - } - get valueSchema() { - return this._def.valueType; - } - _parse(input) { - const { status, ctx } = this._processInputParams(input); - if (ctx.parsedType !== ZodParsedType.object) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.object, - received: ctx.parsedType, - }); - return INVALID; - } - const pairs = []; - const keyType = this._def.keyType; - const valueType = this._def.valueType; - for (const key in ctx.data) { - pairs.push({ - key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, key)), - value: valueType._parse(new ParseInputLazyPath(ctx, ctx.data[key], ctx.path, key)), - alwaysSet: key in ctx.data, - }); - } - if (ctx.common.async) { - return ParseStatus.mergeObjectAsync(status, pairs); - } - else { - return ParseStatus.mergeObjectSync(status, pairs); - } - } - get element() { - return this._def.valueType; - } - static create(first, second, third) { - if (second instanceof ZodType) { - return new ZodRecord({ - keyType: first, - valueType: second, - typeName: ZodFirstPartyTypeKind.ZodRecord, - ...processCreateParams(third), - }); - } - return new ZodRecord({ - keyType: ZodString.create(), - valueType: first, - typeName: ZodFirstPartyTypeKind.ZodRecord, - ...processCreateParams(second), - }); - } -} -class ZodMap extends ZodType { - get keySchema() { - return this._def.keyType; - } - get valueSchema() { - return this._def.valueType; - } - _parse(input) { - const { status, ctx } = this._processInputParams(input); - if (ctx.parsedType !== ZodParsedType.map) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.map, - received: ctx.parsedType, - }); - return INVALID; - } - const keyType = this._def.keyType; - const valueType = this._def.valueType; - const pairs = [...ctx.data.entries()].map(([key, value], index) => { - return { - key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index, "key"])), - value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index, "value"])), - }; - }); - if (ctx.common.async) { - const finalMap = new Map(); - return Promise.resolve().then(async () => { - for (const pair of pairs) { - const key = await pair.key; - const value = await pair.value; - if (key.status === "aborted" || value.status === "aborted") { - return INVALID; - } - if (key.status === "dirty" || value.status === "dirty") { - status.dirty(); - } - finalMap.set(key.value, value.value); - } - return { status: status.value, value: finalMap }; - }); - } - else { - const finalMap = new Map(); - for (const pair of pairs) { - const key = pair.key; - const value = pair.value; - if (key.status === "aborted" || value.status === "aborted") { - return INVALID; - } - if (key.status === "dirty" || value.status === "dirty") { - status.dirty(); - } - finalMap.set(key.value, value.value); - } - return { status: status.value, value: finalMap }; - } - } -} -ZodMap.create = (keyType, valueType, params) => { - return new ZodMap({ - valueType, - keyType, - typeName: ZodFirstPartyTypeKind.ZodMap, - ...processCreateParams(params), - }); -}; -class ZodSet extends ZodType { - _parse(input) { - const { status, ctx } = this._processInputParams(input); - if (ctx.parsedType !== ZodParsedType.set) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.set, - received: ctx.parsedType, - }); - return INVALID; - } - const def = this._def; - if (def.minSize !== null) { - if (ctx.data.size < def.minSize.value) { - addIssueToContext(ctx, { - code: ZodIssueCode.too_small, - minimum: def.minSize.value, - type: "set", - inclusive: true, - exact: false, - message: def.minSize.message, - }); - status.dirty(); - } - } - if (def.maxSize !== null) { - if (ctx.data.size > def.maxSize.value) { - addIssueToContext(ctx, { - code: ZodIssueCode.too_big, - maximum: def.maxSize.value, - type: "set", - inclusive: true, - exact: false, - message: def.maxSize.message, - }); - status.dirty(); - } - } - const valueType = this._def.valueType; - function finalizeSet(elements) { - const parsedSet = new Set(); - for (const element of elements) { - if (element.status === "aborted") - return INVALID; - if (element.status === "dirty") - status.dirty(); - parsedSet.add(element.value); - } - return { status: status.value, value: parsedSet }; - } - const elements = [...ctx.data.values()].map((item, i) => valueType._parse(new ParseInputLazyPath(ctx, item, ctx.path, i))); - if (ctx.common.async) { - return Promise.all(elements).then((elements) => finalizeSet(elements)); - } - else { - return finalizeSet(elements); - } - } - min(minSize, message) { - return new ZodSet({ - ...this._def, - minSize: { value: minSize, message: errorUtil.toString(message) }, - }); - } - max(maxSize, message) { - return new ZodSet({ - ...this._def, - maxSize: { value: maxSize, message: errorUtil.toString(message) }, - }); - } - size(size, message) { - return this.min(size, message).max(size, message); - } - nonempty(message) { - return this.min(1, message); - } -} -ZodSet.create = (valueType, params) => { - return new ZodSet({ - valueType, - minSize: null, - maxSize: null, - typeName: ZodFirstPartyTypeKind.ZodSet, - ...processCreateParams(params), - }); -}; -class ZodFunction extends ZodType { - constructor() { - super(...arguments); - this.validate = this.implement; - } - _parse(input) { - const { ctx } = this._processInputParams(input); - if (ctx.parsedType !== ZodParsedType.function) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.function, - received: ctx.parsedType, - }); - return INVALID; - } - function makeArgsIssue(args, error) { - return makeIssue({ - data: args, - path: ctx.path, - errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), locales_en].filter((x) => !!x), - issueData: { - code: ZodIssueCode.invalid_arguments, - argumentsError: error, - }, - }); - } - function makeReturnsIssue(returns, error) { - return makeIssue({ - data: returns, - path: ctx.path, - errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), locales_en].filter((x) => !!x), - issueData: { - code: ZodIssueCode.invalid_return_type, - returnTypeError: error, - }, - }); - } - const params = { errorMap: ctx.common.contextualErrorMap }; - const fn = ctx.data; - if (this._def.returns instanceof ZodPromise) { - // Would love a way to avoid disabling this rule, but we need - // an alias (using an arrow function was what caused 2651). - // eslint-disable-next-line @typescript-eslint/no-this-alias - const me = this; - return OK(async function (...args) { - const error = new ZodError([]); - const parsedArgs = await me._def.args.parseAsync(args, params).catch((e) => { - error.addIssue(makeArgsIssue(args, e)); - throw error; - }); - const result = await Reflect.apply(fn, this, parsedArgs); - const parsedReturns = await me._def.returns._def.type - .parseAsync(result, params) - .catch((e) => { - error.addIssue(makeReturnsIssue(result, e)); - throw error; - }); - return parsedReturns; - }); - } - else { - // Would love a way to avoid disabling this rule, but we need - // an alias (using an arrow function was what caused 2651). - // eslint-disable-next-line @typescript-eslint/no-this-alias - const me = this; - return OK(function (...args) { - const parsedArgs = me._def.args.safeParse(args, params); - if (!parsedArgs.success) { - throw new ZodError([makeArgsIssue(args, parsedArgs.error)]); - } - const result = Reflect.apply(fn, this, parsedArgs.data); - const parsedReturns = me._def.returns.safeParse(result, params); - if (!parsedReturns.success) { - throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]); - } - return parsedReturns.data; - }); - } - } - parameters() { - return this._def.args; - } - returnType() { - return this._def.returns; - } - args(...items) { - return new ZodFunction({ - ...this._def, - args: ZodTuple.create(items).rest(ZodUnknown.create()), - }); - } - returns(returnType) { - return new ZodFunction({ - ...this._def, - returns: returnType, - }); - } - implement(func) { - const validatedFunc = this.parse(func); - return validatedFunc; - } - strictImplement(func) { - const validatedFunc = this.parse(func); - return validatedFunc; - } - static create(args, returns, params) { - return new ZodFunction({ - args: (args ? args : ZodTuple.create([]).rest(ZodUnknown.create())), - returns: returns || ZodUnknown.create(), - typeName: ZodFirstPartyTypeKind.ZodFunction, - ...processCreateParams(params), - }); - } -} -class ZodLazy extends ZodType { - get schema() { - return this._def.getter(); - } - _parse(input) { - const { ctx } = this._processInputParams(input); - const lazySchema = this._def.getter(); - return lazySchema._parse({ data: ctx.data, path: ctx.path, parent: ctx }); - } -} -ZodLazy.create = (getter, params) => { - return new ZodLazy({ - getter: getter, - typeName: ZodFirstPartyTypeKind.ZodLazy, - ...processCreateParams(params), - }); -}; -class ZodLiteral extends ZodType { - _parse(input) { - if (input.data !== this._def.value) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - received: ctx.data, - code: ZodIssueCode.invalid_literal, - expected: this._def.value, - }); - return INVALID; - } - return { status: "valid", value: input.data }; - } - get value() { - return this._def.value; - } -} -ZodLiteral.create = (value, params) => { - return new ZodLiteral({ - value: value, - typeName: ZodFirstPartyTypeKind.ZodLiteral, - ...processCreateParams(params), - }); -}; -function createZodEnum(values, params) { - return new ZodEnum({ - values, - typeName: ZodFirstPartyTypeKind.ZodEnum, - ...processCreateParams(params), - }); -} -class ZodEnum extends ZodType { - _parse(input) { - if (typeof input.data !== "string") { - const ctx = this._getOrReturnCtx(input); - const expectedValues = this._def.values; - addIssueToContext(ctx, { - expected: util.joinValues(expectedValues), - received: ctx.parsedType, - code: ZodIssueCode.invalid_type, - }); - return INVALID; - } - if (!this._cache) { - this._cache = new Set(this._def.values); - } - if (!this._cache.has(input.data)) { - const ctx = this._getOrReturnCtx(input); - const expectedValues = this._def.values; - addIssueToContext(ctx, { - received: ctx.data, - code: ZodIssueCode.invalid_enum_value, - options: expectedValues, - }); - return INVALID; - } - return OK(input.data); - } - get options() { - return this._def.values; - } - get enum() { - const enumValues = {}; - for (const val of this._def.values) { - enumValues[val] = val; - } - return enumValues; - } - get Values() { - const enumValues = {}; - for (const val of this._def.values) { - enumValues[val] = val; - } - return enumValues; - } - get Enum() { - const enumValues = {}; - for (const val of this._def.values) { - enumValues[val] = val; - } - return enumValues; - } - extract(values, newDef = this._def) { - return ZodEnum.create(values, { - ...this._def, - ...newDef, - }); - } - exclude(values, newDef = this._def) { - return ZodEnum.create(this.options.filter((opt) => !values.includes(opt)), { - ...this._def, - ...newDef, - }); - } -} -ZodEnum.create = createZodEnum; -class ZodNativeEnum extends ZodType { - _parse(input) { - const nativeEnumValues = util.getValidEnumValues(this._def.values); - const ctx = this._getOrReturnCtx(input); - if (ctx.parsedType !== ZodParsedType.string && ctx.parsedType !== ZodParsedType.number) { - const expectedValues = util.objectValues(nativeEnumValues); - addIssueToContext(ctx, { - expected: util.joinValues(expectedValues), - received: ctx.parsedType, - code: ZodIssueCode.invalid_type, - }); - return INVALID; - } - if (!this._cache) { - this._cache = new Set(util.getValidEnumValues(this._def.values)); - } - if (!this._cache.has(input.data)) { - const expectedValues = util.objectValues(nativeEnumValues); - addIssueToContext(ctx, { - received: ctx.data, - code: ZodIssueCode.invalid_enum_value, - options: expectedValues, - }); - return INVALID; - } - return OK(input.data); - } - get enum() { - return this._def.values; - } -} -ZodNativeEnum.create = (values, params) => { - return new ZodNativeEnum({ - values: values, - typeName: ZodFirstPartyTypeKind.ZodNativeEnum, - ...processCreateParams(params), - }); -}; -class ZodPromise extends ZodType { - unwrap() { - return this._def.type; - } - _parse(input) { - const { ctx } = this._processInputParams(input); - if (ctx.parsedType !== ZodParsedType.promise && ctx.common.async === false) { - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.promise, - received: ctx.parsedType, - }); - return INVALID; - } - const promisified = ctx.parsedType === ZodParsedType.promise ? ctx.data : Promise.resolve(ctx.data); - return OK(promisified.then((data) => { - return this._def.type.parseAsync(data, { - path: ctx.path, - errorMap: ctx.common.contextualErrorMap, - }); - })); - } -} -ZodPromise.create = (schema, params) => { - return new ZodPromise({ - type: schema, - typeName: ZodFirstPartyTypeKind.ZodPromise, - ...processCreateParams(params), - }); -}; -class ZodEffects extends ZodType { - innerType() { - return this._def.schema; - } - sourceType() { - return this._def.schema._def.typeName === ZodFirstPartyTypeKind.ZodEffects - ? this._def.schema.sourceType() - : this._def.schema; - } - _parse(input) { - const { status, ctx } = this._processInputParams(input); - const effect = this._def.effect || null; - const checkCtx = { - addIssue: (arg) => { - addIssueToContext(ctx, arg); - if (arg.fatal) { - status.abort(); - } - else { - status.dirty(); - } - }, - get path() { - return ctx.path; - }, - }; - checkCtx.addIssue = checkCtx.addIssue.bind(checkCtx); - if (effect.type === "preprocess") { - const processed = effect.transform(ctx.data, checkCtx); - if (ctx.common.async) { - return Promise.resolve(processed).then(async (processed) => { - if (status.value === "aborted") - return INVALID; - const result = await this._def.schema._parseAsync({ - data: processed, - path: ctx.path, - parent: ctx, - }); - if (result.status === "aborted") - return INVALID; - if (result.status === "dirty") - return DIRTY(result.value); - if (status.value === "dirty") - return DIRTY(result.value); - return result; - }); - } - else { - if (status.value === "aborted") - return INVALID; - const result = this._def.schema._parseSync({ - data: processed, - path: ctx.path, - parent: ctx, - }); - if (result.status === "aborted") - return INVALID; - if (result.status === "dirty") - return DIRTY(result.value); - if (status.value === "dirty") - return DIRTY(result.value); - return result; - } - } - if (effect.type === "refinement") { - const executeRefinement = (acc) => { - const result = effect.refinement(acc, checkCtx); - if (ctx.common.async) { - return Promise.resolve(result); - } - if (result instanceof Promise) { - throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead."); - } - return acc; - }; - if (ctx.common.async === false) { - const inner = this._def.schema._parseSync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - }); - if (inner.status === "aborted") - return INVALID; - if (inner.status === "dirty") - status.dirty(); - // return value is ignored - executeRefinement(inner.value); - return { status: status.value, value: inner.value }; - } - else { - return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => { - if (inner.status === "aborted") - return INVALID; - if (inner.status === "dirty") - status.dirty(); - return executeRefinement(inner.value).then(() => { - return { status: status.value, value: inner.value }; - }); - }); - } - } - if (effect.type === "transform") { - if (ctx.common.async === false) { - const base = this._def.schema._parseSync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - }); - if (!isValid(base)) - return INVALID; - const result = effect.transform(base.value, checkCtx); - if (result instanceof Promise) { - throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`); - } - return { status: status.value, value: result }; - } - else { - return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => { - if (!isValid(base)) - return INVALID; - return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({ - status: status.value, - value: result, - })); - }); - } - } - util.assertNever(effect); - } -} -ZodEffects.create = (schema, effect, params) => { - return new ZodEffects({ - schema, - typeName: ZodFirstPartyTypeKind.ZodEffects, - effect, - ...processCreateParams(params), - }); -}; -ZodEffects.createWithPreprocess = (preprocess, schema, params) => { - return new ZodEffects({ - schema, - effect: { type: "preprocess", transform: preprocess }, - typeName: ZodFirstPartyTypeKind.ZodEffects, - ...processCreateParams(params), - }); -}; - -class ZodOptional extends ZodType { - _parse(input) { - const parsedType = this._getType(input); - if (parsedType === ZodParsedType.undefined) { - return OK(undefined); - } - return this._def.innerType._parse(input); - } - unwrap() { - return this._def.innerType; - } -} -ZodOptional.create = (type, params) => { - return new ZodOptional({ - innerType: type, - typeName: ZodFirstPartyTypeKind.ZodOptional, - ...processCreateParams(params), - }); -}; -class ZodNullable extends ZodType { - _parse(input) { - const parsedType = this._getType(input); - if (parsedType === ZodParsedType.null) { - return OK(null); - } - return this._def.innerType._parse(input); - } - unwrap() { - return this._def.innerType; - } -} -ZodNullable.create = (type, params) => { - return new ZodNullable({ - innerType: type, - typeName: ZodFirstPartyTypeKind.ZodNullable, - ...processCreateParams(params), - }); -}; -class ZodDefault extends ZodType { - _parse(input) { - const { ctx } = this._processInputParams(input); - let data = ctx.data; - if (ctx.parsedType === ZodParsedType.undefined) { - data = this._def.defaultValue(); - } - return this._def.innerType._parse({ - data, - path: ctx.path, - parent: ctx, - }); - } - removeDefault() { - return this._def.innerType; - } -} -ZodDefault.create = (type, params) => { - return new ZodDefault({ - innerType: type, - typeName: ZodFirstPartyTypeKind.ZodDefault, - defaultValue: typeof params.default === "function" ? params.default : () => params.default, - ...processCreateParams(params), - }); -}; -class ZodCatch extends ZodType { - _parse(input) { - const { ctx } = this._processInputParams(input); - // newCtx is used to not collect issues from inner types in ctx - const newCtx = { - ...ctx, - common: { - ...ctx.common, - issues: [], - }, - }; - const result = this._def.innerType._parse({ - data: newCtx.data, - path: newCtx.path, - parent: { - ...newCtx, - }, - }); - if (isAsync(result)) { - return result.then((result) => { - return { - status: "valid", - value: result.status === "valid" - ? result.value - : this._def.catchValue({ - get error() { - return new ZodError(newCtx.common.issues); - }, - input: newCtx.data, - }), - }; - }); - } - else { - return { - status: "valid", - value: result.status === "valid" - ? result.value - : this._def.catchValue({ - get error() { - return new ZodError(newCtx.common.issues); - }, - input: newCtx.data, - }), - }; - } - } - removeCatch() { - return this._def.innerType; - } -} -ZodCatch.create = (type, params) => { - return new ZodCatch({ - innerType: type, - typeName: ZodFirstPartyTypeKind.ZodCatch, - catchValue: typeof params.catch === "function" ? params.catch : () => params.catch, - ...processCreateParams(params), - }); -}; -class ZodNaN extends ZodType { - _parse(input) { - const parsedType = this._getType(input); - if (parsedType !== ZodParsedType.nan) { - const ctx = this._getOrReturnCtx(input); - addIssueToContext(ctx, { - code: ZodIssueCode.invalid_type, - expected: ZodParsedType.nan, - received: ctx.parsedType, - }); - return INVALID; - } - return { status: "valid", value: input.data }; - } -} -ZodNaN.create = (params) => { - return new ZodNaN({ - typeName: ZodFirstPartyTypeKind.ZodNaN, - ...processCreateParams(params), - }); -}; -const BRAND = Symbol("zod_brand"); -class ZodBranded extends ZodType { - _parse(input) { - const { ctx } = this._processInputParams(input); - const data = ctx.data; - return this._def.type._parse({ - data, - path: ctx.path, - parent: ctx, - }); - } - unwrap() { - return this._def.type; - } -} -class ZodPipeline extends ZodType { - _parse(input) { - const { status, ctx } = this._processInputParams(input); - if (ctx.common.async) { - const handleAsync = async () => { - const inResult = await this._def.in._parseAsync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - }); - if (inResult.status === "aborted") - return INVALID; - if (inResult.status === "dirty") { - status.dirty(); - return DIRTY(inResult.value); - } - else { - return this._def.out._parseAsync({ - data: inResult.value, - path: ctx.path, - parent: ctx, - }); - } - }; - return handleAsync(); - } - else { - const inResult = this._def.in._parseSync({ - data: ctx.data, - path: ctx.path, - parent: ctx, - }); - if (inResult.status === "aborted") - return INVALID; - if (inResult.status === "dirty") { - status.dirty(); - return { - status: "dirty", - value: inResult.value, - }; - } - else { - return this._def.out._parseSync({ - data: inResult.value, - path: ctx.path, - parent: ctx, - }); - } - } - } - static create(a, b) { - return new ZodPipeline({ - in: a, - out: b, - typeName: ZodFirstPartyTypeKind.ZodPipeline, - }); - } -} -class ZodReadonly extends ZodType { - _parse(input) { - const result = this._def.innerType._parse(input); - const freeze = (data) => { - if (isValid(data)) { - data.value = Object.freeze(data.value); - } - return data; - }; - return isAsync(result) ? result.then((data) => freeze(data)) : freeze(result); - } - unwrap() { - return this._def.innerType; - } -} -ZodReadonly.create = (type, params) => { - return new ZodReadonly({ - innerType: type, - typeName: ZodFirstPartyTypeKind.ZodReadonly, - ...processCreateParams(params), - }); -}; -//////////////////////////////////////// -//////////////////////////////////////// -////////// ////////// -////////// z.custom ////////// -////////// ////////// -//////////////////////////////////////// -//////////////////////////////////////// -function cleanParams(params, data) { - const p = typeof params === "function" ? params(data) : typeof params === "string" ? { message: params } : params; - const p2 = typeof p === "string" ? { message: p } : p; - return p2; -} -function custom(check, _params = {}, -/** - * @deprecated - * - * Pass `fatal` into the params object instead: - * - * ```ts - * z.string().custom((val) => val.length > 5, { fatal: false }) - * ``` - * - */ -fatal) { - if (check) - return ZodAny.create().superRefine((data, ctx) => { - const r = check(data); - if (r instanceof Promise) { - return r.then((r) => { - if (!r) { - const params = cleanParams(_params, data); - const _fatal = params.fatal ?? fatal ?? true; - ctx.addIssue({ code: "custom", ...params, fatal: _fatal }); - } - }); - } - if (!r) { - const params = cleanParams(_params, data); - const _fatal = params.fatal ?? fatal ?? true; - ctx.addIssue({ code: "custom", ...params, fatal: _fatal }); - } - return; - }); - return ZodAny.create(); -} - -const late = { - object: ZodObject.lazycreate, -}; -var ZodFirstPartyTypeKind; -(function (ZodFirstPartyTypeKind) { - ZodFirstPartyTypeKind["ZodString"] = "ZodString"; - ZodFirstPartyTypeKind["ZodNumber"] = "ZodNumber"; - ZodFirstPartyTypeKind["ZodNaN"] = "ZodNaN"; - ZodFirstPartyTypeKind["ZodBigInt"] = "ZodBigInt"; - ZodFirstPartyTypeKind["ZodBoolean"] = "ZodBoolean"; - ZodFirstPartyTypeKind["ZodDate"] = "ZodDate"; - ZodFirstPartyTypeKind["ZodSymbol"] = "ZodSymbol"; - ZodFirstPartyTypeKind["ZodUndefined"] = "ZodUndefined"; - ZodFirstPartyTypeKind["ZodNull"] = "ZodNull"; - ZodFirstPartyTypeKind["ZodAny"] = "ZodAny"; - ZodFirstPartyTypeKind["ZodUnknown"] = "ZodUnknown"; - ZodFirstPartyTypeKind["ZodNever"] = "ZodNever"; - ZodFirstPartyTypeKind["ZodVoid"] = "ZodVoid"; - ZodFirstPartyTypeKind["ZodArray"] = "ZodArray"; - ZodFirstPartyTypeKind["ZodObject"] = "ZodObject"; - ZodFirstPartyTypeKind["ZodUnion"] = "ZodUnion"; - ZodFirstPartyTypeKind["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion"; - ZodFirstPartyTypeKind["ZodIntersection"] = "ZodIntersection"; - ZodFirstPartyTypeKind["ZodTuple"] = "ZodTuple"; - ZodFirstPartyTypeKind["ZodRecord"] = "ZodRecord"; - ZodFirstPartyTypeKind["ZodMap"] = "ZodMap"; - ZodFirstPartyTypeKind["ZodSet"] = "ZodSet"; - ZodFirstPartyTypeKind["ZodFunction"] = "ZodFunction"; - ZodFirstPartyTypeKind["ZodLazy"] = "ZodLazy"; - ZodFirstPartyTypeKind["ZodLiteral"] = "ZodLiteral"; - ZodFirstPartyTypeKind["ZodEnum"] = "ZodEnum"; - ZodFirstPartyTypeKind["ZodEffects"] = "ZodEffects"; - ZodFirstPartyTypeKind["ZodNativeEnum"] = "ZodNativeEnum"; - ZodFirstPartyTypeKind["ZodOptional"] = "ZodOptional"; - ZodFirstPartyTypeKind["ZodNullable"] = "ZodNullable"; - ZodFirstPartyTypeKind["ZodDefault"] = "ZodDefault"; - ZodFirstPartyTypeKind["ZodCatch"] = "ZodCatch"; - ZodFirstPartyTypeKind["ZodPromise"] = "ZodPromise"; - ZodFirstPartyTypeKind["ZodBranded"] = "ZodBranded"; - ZodFirstPartyTypeKind["ZodPipeline"] = "ZodPipeline"; - ZodFirstPartyTypeKind["ZodReadonly"] = "ZodReadonly"; -})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {})); -// requires TS 4.4+ -class types_Class { - constructor(..._) { } -} -const instanceOfType = ( -// const instanceOfType = any>( -cls, params = { - message: `Input not instance of ${cls.name}`, -}) => custom((data) => data instanceof cls, params); -const stringType = ZodString.create; -const numberType = ZodNumber.create; -const nanType = ZodNaN.create; -const bigIntType = ZodBigInt.create; -const booleanType = ZodBoolean.create; -const dateType = ZodDate.create; -const symbolType = ZodSymbol.create; -const undefinedType = ZodUndefined.create; -const nullType = ZodNull.create; -const anyType = ZodAny.create; -const unknownType = ZodUnknown.create; -const neverType = ZodNever.create; -const voidType = ZodVoid.create; -const arrayType = ZodArray.create; -const objectType = ZodObject.create; -const strictObjectType = ZodObject.strictCreate; -const unionType = ZodUnion.create; -const discriminatedUnionType = ZodDiscriminatedUnion.create; -const intersectionType = ZodIntersection.create; -const tupleType = ZodTuple.create; -const recordType = ZodRecord.create; -const mapType = ZodMap.create; -const setType = ZodSet.create; -const functionType = ZodFunction.create; -const lazyType = ZodLazy.create; -const literalType = ZodLiteral.create; -const enumType = ZodEnum.create; -const nativeEnumType = ZodNativeEnum.create; -const promiseType = ZodPromise.create; -const effectsType = ZodEffects.create; -const optionalType = ZodOptional.create; -const nullableType = ZodNullable.create; -const preprocessType = ZodEffects.createWithPreprocess; -const pipelineType = ZodPipeline.create; -const ostring = () => stringType().optional(); -const onumber = () => numberType().optional(); -const oboolean = () => booleanType().optional(); -const coerce = { - string: ((arg) => ZodString.create({ ...arg, coerce: true })), - number: ((arg) => ZodNumber.create({ ...arg, coerce: true })), - boolean: ((arg) => ZodBoolean.create({ - ...arg, - coerce: true, - })), - bigint: ((arg) => ZodBigInt.create({ ...arg, coerce: true })), - date: ((arg) => ZodDate.create({ ...arg, coerce: true })), -}; - -const types_NEVER = INVALID; - -;// CONCATENATED MODULE: ./node_modules/zod/v3/external.js - - - - - - - -;// CONCATENATED MODULE: ./node_modules/zod/v3/index.js - - - -/* harmony default export */ const zod_v3 = ((/* unused pure expression or super */ null && (z))); - -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/array.js - - - - -//#region src/utils/zod-to-json-schema/parsers/array.ts -function parseArrayDef(def, refs) { - const res = { type: "array" }; - if (def.type?._def && def.type?._def?.typeName !== ZodFirstPartyTypeKind.ZodAny) res.items = parseDef(def.type._def, { - ...refs, - currentPath: [...refs.currentPath, "items"] - }); - if (def.minLength) setResponseValueAndErrors(res, "minItems", def.minLength.value, def.minLength.message, refs); - if (def.maxLength) setResponseValueAndErrors(res, "maxItems", def.maxLength.value, def.maxLength.message, refs); - if (def.exactLength) { - setResponseValueAndErrors(res, "minItems", def.exactLength.value, def.exactLength.message, refs); - setResponseValueAndErrors(res, "maxItems", def.exactLength.value, def.exactLength.message, refs); - } - return res; -} - -//#endregion - -//# sourceMappingURL=array.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/bigint.js - - -//#region src/utils/zod-to-json-schema/parsers/bigint.ts -function parseBigintDef(def, refs) { - const res = { - type: "integer", - format: "int64" - }; - if (!def.checks) return res; - for (const check of def.checks) switch (check.kind) { - case "min": - if (refs.target === "jsonSchema7") if (check.inclusive) setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); - else setResponseValueAndErrors(res, "exclusiveMinimum", check.value, check.message, refs); - else { - if (!check.inclusive) res.exclusiveMinimum = true; - setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); - } - break; - case "max": - if (refs.target === "jsonSchema7") if (check.inclusive) setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); - else setResponseValueAndErrors(res, "exclusiveMaximum", check.value, check.message, refs); - else { - if (!check.inclusive) res.exclusiveMaximum = true; - setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); - } - break; - case "multipleOf": - setResponseValueAndErrors(res, "multipleOf", check.value, check.message, refs); - break; - } - return res; -} - -//#endregion - -//# sourceMappingURL=bigint.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/boolean.js -//#region src/utils/zod-to-json-schema/parsers/boolean.ts -function parseBooleanDef() { - return { type: "boolean" }; -} - -//#endregion - -//# sourceMappingURL=boolean.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/branded.js - - -//#region src/utils/zod-to-json-schema/parsers/branded.ts -function parseBrandedDef(_def, refs) { - return parseDef(_def.type._def, refs); -} - -//#endregion - -//# sourceMappingURL=branded.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/catch.js - - -//#region src/utils/zod-to-json-schema/parsers/catch.ts -const parseCatchDef = (def, refs) => { - return parseDef(def.innerType._def, refs); -}; - -//#endregion - -//# sourceMappingURL=catch.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/date.js - - -//#region src/utils/zod-to-json-schema/parsers/date.ts -function parseDateDef(def, refs, overrideDateStrategy) { - const strategy = overrideDateStrategy ?? refs.dateStrategy; - if (Array.isArray(strategy)) return { anyOf: strategy.map((item) => parseDateDef(def, refs, item)) }; - switch (strategy) { - case "string": - case "format:date-time": return { - type: "string", - format: "date-time" - }; - case "format:date": return { - type: "string", - format: "date" - }; - case "integer": return integerDateParser(def, refs); - } -} -const integerDateParser = (def, refs) => { - const res = { - type: "integer", - format: "unix-time" - }; - if (refs.target === "openApi3") return res; - for (const check of def.checks) switch (check.kind) { - case "min": - setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); - break; - case "max": - setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); - break; - } - return res; -}; - -//#endregion - -//# sourceMappingURL=date.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/default.js - - -//#region src/utils/zod-to-json-schema/parsers/default.ts -function parseDefaultDef(_def, refs) { - return { - ...parseDef(_def.innerType._def, refs), - default: _def.defaultValue() - }; -} - -//#endregion - -//# sourceMappingURL=default.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/effects.js - - - -//#region src/utils/zod-to-json-schema/parsers/effects.ts -function parseEffectsDef(_def, refs) { - return refs.effectStrategy === "input" ? parseDef(_def.schema._def, refs) : parseAnyDef(refs); -} - -//#endregion - -//# sourceMappingURL=effects.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/enum.js -//#region src/utils/zod-to-json-schema/parsers/enum.ts -function parseEnumDef(def) { - return { - type: "string", - enum: Array.from(def.values) - }; -} - -//#endregion - -//# sourceMappingURL=enum.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/intersection.js - - -//#region src/utils/zod-to-json-schema/parsers/intersection.ts -const isJsonSchema7AllOfType = (type) => { - if ("type" in type && type.type === "string") return false; - return "allOf" in type; -}; -function parseIntersectionDef(def, refs) { - const allOf = [parseDef(def.left._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "allOf", - "0" - ] - }), parseDef(def.right._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "allOf", - "1" - ] - })].filter((x) => !!x); - let unevaluatedProperties = refs.target === "jsonSchema2019-09" ? { unevaluatedProperties: false } : void 0; - const mergedAllOf = []; - allOf.forEach((schema) => { - if (isJsonSchema7AllOfType(schema)) { - mergedAllOf.push(...schema.allOf); - if (schema.unevaluatedProperties === void 0) unevaluatedProperties = void 0; - } else { - let nestedSchema = schema; - if ("additionalProperties" in schema && schema.additionalProperties === false) { - const { additionalProperties,...rest } = schema; - nestedSchema = rest; - } else unevaluatedProperties = void 0; - mergedAllOf.push(nestedSchema); - } - }); - return mergedAllOf.length ? { - allOf: mergedAllOf, - ...unevaluatedProperties - } : void 0; -} - -//#endregion - -//# sourceMappingURL=intersection.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/literal.js -//#region src/utils/zod-to-json-schema/parsers/literal.ts -function parseLiteralDef(def, refs) { - const parsedType = typeof def.value; - if (parsedType !== "bigint" && parsedType !== "number" && parsedType !== "boolean" && parsedType !== "string") return { type: Array.isArray(def.value) ? "array" : "object" }; - if (refs.target === "openApi3") return { - type: parsedType === "bigint" ? "integer" : parsedType, - enum: [def.value] - }; - return { - type: parsedType === "bigint" ? "integer" : parsedType, - const: def.value - }; -} - -//#endregion - -//# sourceMappingURL=literal.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/string.js - - -//#region src/utils/zod-to-json-schema/parsers/string.ts -let string_emojiRegex = void 0; -/** -* Generated from the regular expressions found here as of 2024-05-22: -* https://github.com/colinhacks/zod/blob/master/src/types.ts. -* -* Expressions with /i flag have been changed accordingly. -*/ -const zodPatterns = { - cuid: /^[cC][^\s-]{8,}$/, - cuid2: /^[0-9a-z]+$/, - ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/, - email: /^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/, - emoji: () => { - if (string_emojiRegex === void 0) string_emojiRegex = RegExp("^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$", "u"); - return string_emojiRegex; - }, - uuid: /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/, - ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/, - ipv4Cidr: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/, - ipv6: /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/, - ipv6Cidr: /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/, - base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/, - base64url: /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/, - nanoid: /^[a-zA-Z0-9_-]{21}$/, - jwt: /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/ -}; -function parseStringDef(def, refs) { - const res = { type: "string" }; - if (def.checks) for (const check of def.checks) switch (check.kind) { - case "min": - setResponseValueAndErrors(res, "minLength", typeof res.minLength === "number" ? Math.max(res.minLength, check.value) : check.value, check.message, refs); - break; - case "max": - setResponseValueAndErrors(res, "maxLength", typeof res.maxLength === "number" ? Math.min(res.maxLength, check.value) : check.value, check.message, refs); - break; - case "email": - switch (refs.emailStrategy) { - case "format:email": - addFormat(res, "email", check.message, refs); - break; - case "format:idn-email": - addFormat(res, "idn-email", check.message, refs); - break; - case "pattern:zod": - addPattern(res, zodPatterns.email, check.message, refs); - break; - } - break; - case "url": - addFormat(res, "uri", check.message, refs); - break; - case "uuid": - addFormat(res, "uuid", check.message, refs); - break; - case "regex": - addPattern(res, check.regex, check.message, refs); - break; - case "cuid": - addPattern(res, zodPatterns.cuid, check.message, refs); - break; - case "cuid2": - addPattern(res, zodPatterns.cuid2, check.message, refs); - break; - case "startsWith": - addPattern(res, RegExp(`^${escapeLiteralCheckValue(check.value, refs)}`), check.message, refs); - break; - case "endsWith": - addPattern(res, RegExp(`${escapeLiteralCheckValue(check.value, refs)}$`), check.message, refs); - break; - case "datetime": - addFormat(res, "date-time", check.message, refs); - break; - case "date": - addFormat(res, "date", check.message, refs); - break; - case "time": - addFormat(res, "time", check.message, refs); - break; - case "duration": - addFormat(res, "duration", check.message, refs); - break; - case "length": - setResponseValueAndErrors(res, "minLength", typeof res.minLength === "number" ? Math.max(res.minLength, check.value) : check.value, check.message, refs); - setResponseValueAndErrors(res, "maxLength", typeof res.maxLength === "number" ? Math.min(res.maxLength, check.value) : check.value, check.message, refs); - break; - case "includes": - addPattern(res, RegExp(escapeLiteralCheckValue(check.value, refs)), check.message, refs); - break; - case "ip": - if (check.version !== "v6") addFormat(res, "ipv4", check.message, refs); - if (check.version !== "v4") addFormat(res, "ipv6", check.message, refs); - break; - case "base64url": - addPattern(res, zodPatterns.base64url, check.message, refs); - break; - case "jwt": - addPattern(res, zodPatterns.jwt, check.message, refs); - break; - case "cidr": - if (check.version !== "v6") addPattern(res, zodPatterns.ipv4Cidr, check.message, refs); - if (check.version !== "v4") addPattern(res, zodPatterns.ipv6Cidr, check.message, refs); - break; - case "emoji": - addPattern(res, zodPatterns.emoji(), check.message, refs); - break; - case "ulid": - addPattern(res, zodPatterns.ulid, check.message, refs); - break; - case "base64": - switch (refs.base64Strategy) { - case "format:binary": - addFormat(res, "binary", check.message, refs); - break; - case "contentEncoding:base64": - setResponseValueAndErrors(res, "contentEncoding", "base64", check.message, refs); - break; - case "pattern:zod": - addPattern(res, zodPatterns.base64, check.message, refs); - break; - } - break; - case "nanoid": - addPattern(res, zodPatterns.nanoid, check.message, refs); - break; - case "toLowerCase": - case "toUpperCase": - case "trim": break; - default: - /* c8 ignore next */ - ((_) => {})(check); - } - return res; -} -function escapeLiteralCheckValue(literal, refs) { - return refs.patternStrategy === "escape" ? escapeNonAlphaNumeric(literal) : literal; -} -const ALPHA_NUMERIC = /* @__PURE__ */ new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789"); -function escapeNonAlphaNumeric(source) { - let result = ""; - for (let i = 0; i < source.length; i++) { - if (!ALPHA_NUMERIC.has(source[i])) result += "\\"; - result += source[i]; - } - return result; -} -function addFormat(schema, value, message, refs) { - if (schema.format || schema.anyOf?.some((x) => x.format)) { - if (!schema.anyOf) schema.anyOf = []; - if (schema.format) { - schema.anyOf.push({ - format: schema.format, - ...schema.errorMessage && refs.errorMessages && { errorMessage: { format: schema.errorMessage.format } } - }); - delete schema.format; - if (schema.errorMessage) { - delete schema.errorMessage.format; - if (Object.keys(schema.errorMessage).length === 0) delete schema.errorMessage; - } - } - schema.anyOf.push({ - format: value, - ...message && refs.errorMessages && { errorMessage: { format: message } } - }); - } else setResponseValueAndErrors(schema, "format", value, message, refs); -} -function addPattern(schema, regex, message, refs) { - if (schema.pattern || schema.allOf?.some((x) => x.pattern)) { - if (!schema.allOf) schema.allOf = []; - if (schema.pattern) { - schema.allOf.push({ - pattern: schema.pattern, - ...schema.errorMessage && refs.errorMessages && { errorMessage: { pattern: schema.errorMessage.pattern } } - }); - delete schema.pattern; - if (schema.errorMessage) { - delete schema.errorMessage.pattern; - if (Object.keys(schema.errorMessage).length === 0) delete schema.errorMessage; - } - } - schema.allOf.push({ - pattern: stringifyRegExpWithFlags(regex, refs), - ...message && refs.errorMessages && { errorMessage: { pattern: message } } - }); - } else setResponseValueAndErrors(schema, "pattern", stringifyRegExpWithFlags(regex, refs), message, refs); -} -function stringifyRegExpWithFlags(regex, refs) { - if (!refs.applyRegexFlags || !regex.flags) return regex.source; - const flags = { - i: regex.flags.includes("i"), - m: regex.flags.includes("m"), - s: regex.flags.includes("s") - }; - const source = flags.i ? regex.source.toLowerCase() : regex.source; - let pattern = ""; - let isEscaped = false; - let inCharGroup = false; - let inCharRange = false; - for (let i = 0; i < source.length; i++) { - if (isEscaped) { - pattern += source[i]; - isEscaped = false; - continue; - } - if (flags.i) { - if (inCharGroup) { - if (source[i].match(/[a-z]/)) { - if (inCharRange) { - pattern += source[i]; - pattern += `${source[i - 2]}-${source[i]}`.toUpperCase(); - inCharRange = false; - } else if (source[i + 1] === "-" && source[i + 2]?.match(/[a-z]/)) { - pattern += source[i]; - inCharRange = true; - } else pattern += `${source[i]}${source[i].toUpperCase()}`; - continue; - } - } else if (source[i].match(/[a-z]/)) { - pattern += `[${source[i]}${source[i].toUpperCase()}]`; - continue; - } - } - if (flags.m) { - if (source[i] === "^") { - pattern += `(^|(?<=[\r\n]))`; - continue; - } else if (source[i] === "$") { - pattern += `($|(?=[\r\n]))`; - continue; - } - } - if (flags.s && source[i] === ".") { - pattern += inCharGroup ? `${source[i]}\r\n` : `[${source[i]}\r\n]`; - continue; - } - pattern += source[i]; - if (source[i] === "\\") isEscaped = true; - else if (inCharGroup && source[i] === "]") inCharGroup = false; - else if (!inCharGroup && source[i] === "[") inCharGroup = true; - } - try { - new RegExp(pattern); - } catch { - console.warn(`Could not convert regex pattern at ${refs.currentPath.join("/")} to a flag-independent form! Falling back to the flag-ignorant source`); - return regex.source; - } - return pattern; -} - -//#endregion - -//# sourceMappingURL=string.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/record.js - - - - - - -//#region src/utils/zod-to-json-schema/parsers/record.ts -function parseRecordDef(def, refs) { - if (refs.target === "openAi") console.warn("Warning: OpenAI may not support records in schemas! Try an array of key-value pairs instead."); - if (refs.target === "openApi3" && def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) return { - type: "object", - required: def.keyType._def.values, - properties: def.keyType._def.values.reduce((acc, key) => ({ - ...acc, - [key]: parseDef(def.valueType._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "properties", - key - ] - }) ?? parseAnyDef(refs) - }), {}), - additionalProperties: refs.rejectedAdditionalProperties - }; - const schema = { - type: "object", - additionalProperties: parseDef(def.valueType._def, { - ...refs, - currentPath: [...refs.currentPath, "additionalProperties"] - }) ?? refs.allowedAdditionalProperties - }; - if (refs.target === "openApi3") return schema; - if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodString && def.keyType._def.checks?.length) { - const { type,...keyType } = parseStringDef(def.keyType._def, refs); - return { - ...schema, - propertyNames: keyType - }; - } else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) return { - ...schema, - propertyNames: { enum: def.keyType._def.values } - }; - else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodBranded && def.keyType._def.type._def.typeName === ZodFirstPartyTypeKind.ZodString && def.keyType._def.type._def.checks?.length) { - const { type,...keyType } = parseBrandedDef(def.keyType._def, refs); - return { - ...schema, - propertyNames: keyType - }; - } - return schema; -} - -//#endregion - -//# sourceMappingURL=record.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/map.js - - - - -//#region src/utils/zod-to-json-schema/parsers/map.ts -function parseMapDef(def, refs) { - if (refs.mapStrategy === "record") return parseRecordDef(def, refs); - const keys = parseDef(def.keyType._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "items", - "items", - "0" - ] - }) || parseAnyDef(refs); - const values = parseDef(def.valueType._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "items", - "items", - "1" - ] - }) || parseAnyDef(refs); - return { - type: "array", - maxItems: 125, - items: { - type: "array", - items: [keys, values], - minItems: 2, - maxItems: 2 - } - }; -} - -//#endregion - -//# sourceMappingURL=map.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/nativeEnum.js -//#region src/utils/zod-to-json-schema/parsers/nativeEnum.ts -function parseNativeEnumDef(def) { - const object = def.values; - const actualKeys = Object.keys(def.values).filter((key) => { - return typeof object[object[key]] !== "number"; - }); - const actualValues = actualKeys.map((key) => object[key]); - const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values))); - return { - type: parsedTypes.length === 1 ? parsedTypes[0] === "string" ? "string" : "number" : ["string", "number"], - enum: actualValues - }; -} - -//#endregion - -//# sourceMappingURL=nativeEnum.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/never.js - - -//#region src/utils/zod-to-json-schema/parsers/never.ts -function parseNeverDef(refs) { - return refs.target === "openAi" ? void 0 : { not: parseAnyDef({ - ...refs, - currentPath: [...refs.currentPath, "not"] - }) }; -} - -//#endregion - -//# sourceMappingURL=never.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/null.js -//#region src/utils/zod-to-json-schema/parsers/null.ts -function parseNullDef(refs) { - return refs.target === "openApi3" ? { - enum: ["null"], - nullable: true - } : { type: "null" }; -} - -//#endregion - -//# sourceMappingURL=null.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/union.js - - -//#region src/utils/zod-to-json-schema/parsers/union.ts -const primitiveMappings = { - ZodString: "string", - ZodNumber: "number", - ZodBigInt: "integer", - ZodBoolean: "boolean", - ZodNull: "null" -}; -function parseUnionDef(def, refs) { - if (refs.target === "openApi3") return asAnyOf(def, refs); - const options = def.options instanceof Map ? Array.from(def.options.values()) : def.options; - if (options.every((x) => x._def.typeName in primitiveMappings && (!x._def.checks || !x._def.checks.length))) { - const types = options.reduce((types$1, x) => { - const type = primitiveMappings[x._def.typeName]; - return type && !types$1.includes(type) ? [...types$1, type] : types$1; - }, []); - return { type: types.length > 1 ? types : types[0] }; - } else if (options.every((x) => x._def.typeName === "ZodLiteral" && !x.description)) { - const types = options.reduce((acc, x) => { - const type = typeof x._def.value; - switch (type) { - case "string": - case "number": - case "boolean": return [...acc, type]; - case "bigint": return [...acc, "integer"]; - case "object": - if (x._def.value === null) return [...acc, "null"]; - return acc; - case "symbol": - case "undefined": - case "function": - default: return acc; - } - }, []); - if (types.length === options.length) { - const uniqueTypes = types.filter((x, i, a) => a.indexOf(x) === i); - return { - type: uniqueTypes.length > 1 ? uniqueTypes : uniqueTypes[0], - enum: options.reduce((acc, x) => { - return acc.includes(x._def.value) ? acc : [...acc, x._def.value]; - }, []) - }; - } - } else if (options.every((x) => x._def.typeName === "ZodEnum")) return { - type: "string", - enum: options.reduce((acc, x) => [...acc, ...x._def.values.filter((x$1) => !acc.includes(x$1))], []) - }; - return asAnyOf(def, refs); -} -const asAnyOf = (def, refs) => { - const anyOf = (def.options instanceof Map ? Array.from(def.options.values()) : def.options).map((x, i) => parseDef(x._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "anyOf", - `${i}` - ] - })).filter((x) => !!x && (!refs.strictUnions || typeof x === "object" && Object.keys(x).length > 0)); - return anyOf.length ? { anyOf } : void 0; -}; - -//#endregion - -//# sourceMappingURL=union.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/nullable.js - - - -//#region src/utils/zod-to-json-schema/parsers/nullable.ts -function parseNullableDef(def, refs) { - if ([ - "ZodString", - "ZodNumber", - "ZodBigInt", - "ZodBoolean", - "ZodNull" - ].includes(def.innerType._def.typeName) && (!def.innerType._def.checks || !def.innerType._def.checks.length)) { - if (refs.target === "openApi3") return { - type: primitiveMappings[def.innerType._def.typeName], - nullable: true - }; - return { type: [primitiveMappings[def.innerType._def.typeName], "null"] }; - } - if (refs.target === "openApi3") { - const base$1 = parseDef(def.innerType._def, { - ...refs, - currentPath: [...refs.currentPath] - }); - if (base$1 && "$ref" in base$1) return { - allOf: [base$1], - nullable: true - }; - return base$1 && { - ...base$1, - nullable: true - }; - } - const base = parseDef(def.innerType._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "anyOf", - "0" - ] - }); - return base && { anyOf: [base, { type: "null" }] }; -} - -//#endregion - -//# sourceMappingURL=nullable.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/number.js - - -//#region src/utils/zod-to-json-schema/parsers/number.ts -function parseNumberDef(def, refs) { - const res = { type: "number" }; - if (!def.checks) return res; - for (const check of def.checks) switch (check.kind) { - case "int": - res.type = "integer"; - addErrorMessage(res, "type", check.message, refs); - break; - case "min": - if (refs.target === "jsonSchema7") if (check.inclusive) setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); - else setResponseValueAndErrors(res, "exclusiveMinimum", check.value, check.message, refs); - else { - if (!check.inclusive) res.exclusiveMinimum = true; - setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); - } - break; - case "max": - if (refs.target === "jsonSchema7") if (check.inclusive) setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); - else setResponseValueAndErrors(res, "exclusiveMaximum", check.value, check.message, refs); - else { - if (!check.inclusive) res.exclusiveMaximum = true; - setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); - } - break; - case "multipleOf": - setResponseValueAndErrors(res, "multipleOf", check.value, check.message, refs); - break; - } - return res; -} - -//#endregion - -//# sourceMappingURL=number.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/object.js - - -//#region src/utils/zod-to-json-schema/parsers/object.ts -function parseObjectDef(def, refs) { - const forceOptionalIntoNullable = refs.target === "openAi"; - const result = { - type: "object", - properties: {} - }; - const required = []; - const shape = def.shape(); - for (const propName in shape) { - let propDef = shape[propName]; - if (propDef === void 0 || propDef._def === void 0) continue; - let propOptional = safeIsOptional(propDef); - if (propOptional && forceOptionalIntoNullable) { - if (propDef._def.typeName === "ZodOptional") propDef = propDef._def.innerType; - if (!propDef.isNullable()) propDef = propDef.nullable(); - propOptional = false; - } - const parsedDef = parseDef(propDef._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "properties", - propName - ], - propertyPath: [ - ...refs.currentPath, - "properties", - propName - ] - }); - if (parsedDef === void 0) continue; - result.properties[propName] = parsedDef; - if (!propOptional) required.push(propName); - } - if (required.length) result.required = required; - const additionalProperties = decideAdditionalProperties(def, refs); - if (additionalProperties !== void 0) result.additionalProperties = additionalProperties; - return result; -} -function decideAdditionalProperties(def, refs) { - if (def.catchall._def.typeName !== "ZodNever") return parseDef(def.catchall._def, { - ...refs, - currentPath: [...refs.currentPath, "additionalProperties"] - }); - switch (def.unknownKeys) { - case "passthrough": return refs.allowedAdditionalProperties; - case "strict": return refs.rejectedAdditionalProperties; - case "strip": return refs.removeAdditionalStrategy === "strict" ? refs.allowedAdditionalProperties : refs.rejectedAdditionalProperties; - } -} -function safeIsOptional(schema) { - try { - return schema.isOptional(); - } catch { - return true; - } -} - -//#endregion - -//# sourceMappingURL=object.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/optional.js - - - -//#region src/utils/zod-to-json-schema/parsers/optional.ts -const parseOptionalDef = (def, refs) => { - if (refs.currentPath.toString() === refs.propertyPath?.toString()) return parseDef(def.innerType._def, refs); - const innerSchema = parseDef(def.innerType._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "anyOf", - "1" - ] - }); - return innerSchema ? { anyOf: [{ not: parseAnyDef(refs) }, innerSchema] } : parseAnyDef(refs); -}; - -//#endregion - -//# sourceMappingURL=optional.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/pipeline.js - - -//#region src/utils/zod-to-json-schema/parsers/pipeline.ts -const parsePipelineDef = (def, refs) => { - if (refs.pipeStrategy === "input") return parseDef(def.in._def, refs); - else if (refs.pipeStrategy === "output") return parseDef(def.out._def, refs); - const a = parseDef(def.in._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "allOf", - "0" - ] - }); - const b = parseDef(def.out._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "allOf", - a ? "1" : "0" - ] - }); - return { allOf: [a, b].filter((x) => x !== void 0) }; -}; - -//#endregion - -//# sourceMappingURL=pipeline.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/promise.js - - -//#region src/utils/zod-to-json-schema/parsers/promise.ts -function parsePromiseDef(def, refs) { - return parseDef(def.type._def, refs); -} - -//#endregion - -//# sourceMappingURL=promise.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/set.js - - - -//#region src/utils/zod-to-json-schema/parsers/set.ts -function parseSetDef(def, refs) { - const items = parseDef(def.valueType._def, { - ...refs, - currentPath: [...refs.currentPath, "items"] - }); - const schema = { - type: "array", - uniqueItems: true, - items - }; - if (def.minSize) setResponseValueAndErrors(schema, "minItems", def.minSize.value, def.minSize.message, refs); - if (def.maxSize) setResponseValueAndErrors(schema, "maxItems", def.maxSize.value, def.maxSize.message, refs); - return schema; -} - -//#endregion - -//# sourceMappingURL=set.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/tuple.js - - -//#region src/utils/zod-to-json-schema/parsers/tuple.ts -function parseTupleDef(def, refs) { - if (def.rest) return { - type: "array", - minItems: def.items.length, - items: def.items.map((x, i) => parseDef(x._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "items", - `${i}` - ] - })).reduce((acc, x) => x === void 0 ? acc : [...acc, x], []), - additionalItems: parseDef(def.rest._def, { - ...refs, - currentPath: [...refs.currentPath, "additionalItems"] - }) - }; - else return { - type: "array", - minItems: def.items.length, - maxItems: def.items.length, - items: def.items.map((x, i) => parseDef(x._def, { - ...refs, - currentPath: [ - ...refs.currentPath, - "items", - `${i}` - ] - })).reduce((acc, x) => x === void 0 ? acc : [...acc, x], []) - }; -} - -//#endregion - -//# sourceMappingURL=tuple.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/undefined.js - - -//#region src/utils/zod-to-json-schema/parsers/undefined.ts -function parseUndefinedDef(refs) { - return { not: parseAnyDef(refs) }; -} - -//#endregion - -//# sourceMappingURL=undefined.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/unknown.js - - -//#region src/utils/zod-to-json-schema/parsers/unknown.ts -function parseUnknownDef(refs) { - return parseAnyDef(refs); -} - -//#endregion - -//# sourceMappingURL=unknown.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/readonly.js - - -//#region src/utils/zod-to-json-schema/parsers/readonly.ts -const parseReadonlyDef = (def, refs) => { - return parseDef(def.innerType._def, refs); -}; - -//#endregion - -//# sourceMappingURL=readonly.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/selectParser.js - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//#region src/utils/zod-to-json-schema/selectParser.ts -const selectParser = (def, typeName, refs) => { - switch (typeName) { - case ZodFirstPartyTypeKind.ZodString: return parseStringDef(def, refs); - case ZodFirstPartyTypeKind.ZodNumber: return parseNumberDef(def, refs); - case ZodFirstPartyTypeKind.ZodObject: return parseObjectDef(def, refs); - case ZodFirstPartyTypeKind.ZodBigInt: return parseBigintDef(def, refs); - case ZodFirstPartyTypeKind.ZodBoolean: return parseBooleanDef(); - case ZodFirstPartyTypeKind.ZodDate: return parseDateDef(def, refs); - case ZodFirstPartyTypeKind.ZodUndefined: return parseUndefinedDef(refs); - case ZodFirstPartyTypeKind.ZodNull: return parseNullDef(refs); - case ZodFirstPartyTypeKind.ZodArray: return parseArrayDef(def, refs); - case ZodFirstPartyTypeKind.ZodUnion: - case ZodFirstPartyTypeKind.ZodDiscriminatedUnion: return parseUnionDef(def, refs); - case ZodFirstPartyTypeKind.ZodIntersection: return parseIntersectionDef(def, refs); - case ZodFirstPartyTypeKind.ZodTuple: return parseTupleDef(def, refs); - case ZodFirstPartyTypeKind.ZodRecord: return parseRecordDef(def, refs); - case ZodFirstPartyTypeKind.ZodLiteral: return parseLiteralDef(def, refs); - case ZodFirstPartyTypeKind.ZodEnum: return parseEnumDef(def); - case ZodFirstPartyTypeKind.ZodNativeEnum: return parseNativeEnumDef(def); - case ZodFirstPartyTypeKind.ZodNullable: return parseNullableDef(def, refs); - case ZodFirstPartyTypeKind.ZodOptional: return parseOptionalDef(def, refs); - case ZodFirstPartyTypeKind.ZodMap: return parseMapDef(def, refs); - case ZodFirstPartyTypeKind.ZodSet: return parseSetDef(def, refs); - case ZodFirstPartyTypeKind.ZodLazy: return () => def.getter()._def; - case ZodFirstPartyTypeKind.ZodPromise: return parsePromiseDef(def, refs); - case ZodFirstPartyTypeKind.ZodNaN: - case ZodFirstPartyTypeKind.ZodNever: return parseNeverDef(refs); - case ZodFirstPartyTypeKind.ZodEffects: return parseEffectsDef(def, refs); - case ZodFirstPartyTypeKind.ZodAny: return parseAnyDef(refs); - case ZodFirstPartyTypeKind.ZodUnknown: return parseUnknownDef(refs); - case ZodFirstPartyTypeKind.ZodDefault: return parseDefaultDef(def, refs); - case ZodFirstPartyTypeKind.ZodBranded: return parseBrandedDef(def, refs); - case ZodFirstPartyTypeKind.ZodReadonly: return parseReadonlyDef(def, refs); - case ZodFirstPartyTypeKind.ZodCatch: return parseCatchDef(def, refs); - case ZodFirstPartyTypeKind.ZodPipeline: return parsePipelineDef(def, refs); - case ZodFirstPartyTypeKind.ZodFunction: - case ZodFirstPartyTypeKind.ZodVoid: - case ZodFirstPartyTypeKind.ZodSymbol: return void 0; - default: - /* c8 ignore next */ - return ((_) => void 0)(typeName); - } -}; - -//#endregion - -//# sourceMappingURL=selectParser.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parseDef.js - - - - - -//#region src/utils/zod-to-json-schema/parseDef.ts -function parseDef(def, refs, forceResolution = false) { - const seenItem = refs.seen.get(def); - if (refs.override) { - const overrideResult = refs.override?.(def, refs, seenItem, forceResolution); - if (overrideResult !== ignoreOverride) return overrideResult; - } - if (seenItem && !forceResolution) { - const seenSchema = get$ref(seenItem, refs); - if (seenSchema !== void 0) return seenSchema; - } - const newItem = { - def, - path: refs.currentPath, - jsonSchema: void 0 - }; - refs.seen.set(def, newItem); - const jsonSchemaOrGetter = selectParser(def, def.typeName, refs); - const jsonSchema = typeof jsonSchemaOrGetter === "function" ? parseDef(jsonSchemaOrGetter(), refs) : jsonSchemaOrGetter; - if (jsonSchema) addMeta(def, refs, jsonSchema); - if (refs.postProcess) { - const postProcessResult = refs.postProcess(jsonSchema, def, refs); - newItem.jsonSchema = jsonSchema; - return postProcessResult; - } - newItem.jsonSchema = jsonSchema; - return jsonSchema; -} -const get$ref = (item, refs) => { - switch (refs.$refStrategy) { - case "root": return { $ref: item.path.join("/") }; - case "relative": return { $ref: getRelativePath(refs.currentPath, item.path) }; - case "none": - case "seen": - if (item.path.length < refs.currentPath.length && item.path.every((value, index) => refs.currentPath[index] === value)) { - console.warn(`Recursive reference detected at ${refs.currentPath.join("/")}! Defaulting to any`); - return parseAnyDef(refs); - } - return refs.$refStrategy === "seen" ? parseAnyDef(refs) : void 0; - } -}; -const addMeta = (def, refs, jsonSchema) => { - if (def.description) { - jsonSchema.description = def.description; - if (refs.markdownDescription) jsonSchema.markdownDescription = def.description; - } - return jsonSchema; -}; - -//#endregion - -//# sourceMappingURL=parseDef.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/zodToJsonSchema.js - - - - -//#region src/utils/zod-to-json-schema/zodToJsonSchema.ts -const zodToJsonSchema_zodToJsonSchema = (schema, options) => { - const refs = getRefs(options); - let definitions = typeof options === "object" && options.definitions ? Object.entries(options.definitions).reduce((acc, [name$1, schema$1]) => ({ - ...acc, - [name$1]: parseDef(schema$1._def, { - ...refs, - currentPath: [ - ...refs.basePath, - refs.definitionPath, - name$1 - ] - }, true) ?? parseAnyDef(refs) - }), {}) : void 0; - const name = typeof options === "string" ? options : options?.nameStrategy === "title" ? void 0 : options?.name; - const main = parseDef(schema._def, name === void 0 ? refs : { - ...refs, - currentPath: [ - ...refs.basePath, - refs.definitionPath, - name - ] - }, false) ?? parseAnyDef(refs); - const title = typeof options === "object" && options.name !== void 0 && options.nameStrategy === "title" ? options.name : void 0; - if (title !== void 0) main.title = title; - if (refs.flags.hasReferencedOpenAiAnyType) { - if (!definitions) definitions = {}; - if (!definitions[refs.openAiAnyTypeName]) definitions[refs.openAiAnyTypeName] = { - type: [ - "string", - "number", - "integer", - "boolean", - "array", - "null" - ], - items: { $ref: refs.$refStrategy === "relative" ? "1" : [ - ...refs.basePath, - refs.definitionPath, - refs.openAiAnyTypeName - ].join("/") } - }; - } - const combined = name === void 0 ? definitions ? { - ...main, - [refs.definitionPath]: definitions - } : main : { - $ref: [ - ...refs.$refStrategy === "relative" ? [] : refs.basePath, - refs.definitionPath, - name - ].join("/"), - [refs.definitionPath]: { - ...definitions, - [name]: main - } - }; - if (refs.target === "jsonSchema7") combined.$schema = "http://json-schema.org/draft-07/schema#"; - else if (refs.target === "jsonSchema2019-09" || refs.target === "openAi") combined.$schema = "https://json-schema.org/draft/2019-09/schema#"; - if (refs.target === "openAi" && ("anyOf" in combined || "oneOf" in combined || "allOf" in combined || "type" in combined && Array.isArray(combined.type))) console.warn("Warning: OpenAI may not support schemas with unions as roots! Try wrapping it in an object property."); - return combined; -}; - -//#endregion - -//# sourceMappingURL=zodToJsonSchema.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/index.js - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/deep-compare-strict.js -function deepCompareStrict(a, b) { - const typeofa = typeof a; - if (typeofa !== typeof b) { - return false; - } - if (Array.isArray(a)) { - if (!Array.isArray(b)) { - return false; - } - const length = a.length; - if (length !== b.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (!deepCompareStrict(a[i], b[i])) { - return false; - } - } - return true; - } - if (typeofa === 'object') { - if (!a || !b) { - return a === b; - } - const aKeys = Object.keys(a); - const bKeys = Object.keys(b); - const length = aKeys.length; - if (length !== bKeys.length) { - return false; - } - for (const k of aKeys) { - if (!deepCompareStrict(a[k], b[k])) { - return false; - } - } - return true; - } - return a === b; -} - -;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/pointer.js -function encodePointer(p) { - return encodeURI(escapePointer(p)); -} -function escapePointer(p) { - return p.replace(/~/g, '~0').replace(/\//g, '~1'); -} - -;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/dereference.js - -const schemaKeyword = { - additionalItems: true, - unevaluatedItems: true, - items: true, - contains: true, - additionalProperties: true, - unevaluatedProperties: true, - propertyNames: true, - not: true, - if: true, - then: true, - else: true -}; -const schemaArrayKeyword = { - prefixItems: true, - items: true, - allOf: true, - anyOf: true, - oneOf: true -}; -const schemaMapKeyword = { - $defs: true, - definitions: true, - properties: true, - patternProperties: true, - dependentSchemas: true -}; -const ignoredKeyword = { - id: true, - $id: true, - $ref: true, - $schema: true, - $anchor: true, - $vocabulary: true, - $comment: true, - default: true, - enum: true, - const: true, - required: true, - type: true, - maximum: true, - minimum: true, - exclusiveMaximum: true, - exclusiveMinimum: true, - multipleOf: true, - maxLength: true, - minLength: true, - pattern: true, - format: true, - maxItems: true, - minItems: true, - uniqueItems: true, - maxProperties: true, - minProperties: true -}; -let initialBaseURI = typeof self !== 'undefined' && - self.location && - self.location.origin !== 'null' - ? - new URL(self.location.origin + self.location.pathname + location.search) - : new URL('https://github.com/cfworker'); -function dereference(schema, lookup = Object.create(null), baseURI = initialBaseURI, basePointer = '') { - if (schema && typeof schema === 'object' && !Array.isArray(schema)) { - const id = schema.$id || schema.id; - if (id) { - const url = new URL(id, baseURI.href); - if (url.hash.length > 1) { - lookup[url.href] = schema; - } - else { - url.hash = ''; - if (basePointer === '') { - baseURI = url; - } - else { - dereference(schema, lookup, baseURI); - } - } - } - } - else if (schema !== true && schema !== false) { - return lookup; - } - const schemaURI = baseURI.href + (basePointer ? '#' + basePointer : ''); - if (lookup[schemaURI] !== undefined) { - throw new Error(`Duplicate schema URI "${schemaURI}".`); - } - lookup[schemaURI] = schema; - if (schema === true || schema === false) { - return lookup; - } - if (schema.__absolute_uri__ === undefined) { - Object.defineProperty(schema, '__absolute_uri__', { - enumerable: false, - value: schemaURI - }); - } - if (schema.$ref && schema.__absolute_ref__ === undefined) { - const url = new URL(schema.$ref, baseURI.href); - url.hash = url.hash; - Object.defineProperty(schema, '__absolute_ref__', { - enumerable: false, - value: url.href - }); - } - if (schema.$recursiveRef && schema.__absolute_recursive_ref__ === undefined) { - const url = new URL(schema.$recursiveRef, baseURI.href); - url.hash = url.hash; - Object.defineProperty(schema, '__absolute_recursive_ref__', { - enumerable: false, - value: url.href - }); - } - if (schema.$anchor) { - const url = new URL('#' + schema.$anchor, baseURI.href); - lookup[url.href] = schema; - } - for (let key in schema) { - if (ignoredKeyword[key]) { - continue; - } - const keyBase = `${basePointer}/${encodePointer(key)}`; - const subSchema = schema[key]; - if (Array.isArray(subSchema)) { - if (schemaArrayKeyword[key]) { - const length = subSchema.length; - for (let i = 0; i < length; i++) { - dereference(subSchema[i], lookup, baseURI, `${keyBase}/${i}`); - } - } - } - else if (schemaMapKeyword[key]) { - for (let subKey in subSchema) { - dereference(subSchema[subKey], lookup, baseURI, `${keyBase}/${encodePointer(subKey)}`); - } - } - else { - dereference(subSchema, lookup, baseURI, keyBase); - } - } - return lookup; -} - -;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/format.js -const DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/; -const DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; -const TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i; -const HOSTNAME = /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i; -const URIREF = /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; -const URITEMPLATE = /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i; -const URL_ = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)(?:\.(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu; -const UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i; -const JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$/; -const JSON_POINTER_URI_FRAGMENT = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i; -const RELATIVE_JSON_POINTER = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/; -const EMAIL = (input) => { - if (input[0] === '"') - return false; - const [name, host, ...rest] = input.split('@'); - if (!name || - !host || - rest.length !== 0 || - name.length > 64 || - host.length > 253) - return false; - if (name[0] === '.' || name.endsWith('.') || name.includes('..')) - return false; - if (!/^[a-z0-9.-]+$/i.test(host) || - !/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+$/i.test(name)) - return false; - return host - .split('.') - .every(part => /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(part)); -}; -const IPV4 = /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/; -const IPV6 = /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i; -const DURATION = (input) => input.length > 1 && - input.length < 80 && - (/^P\d+([.,]\d+)?W$/.test(input) || - (/^P[\dYMDTHS]*(\d[.,]\d+)?[YMDHS]$/.test(input) && - /^P([.,\d]+Y)?([.,\d]+M)?([.,\d]+D)?(T([.,\d]+H)?([.,\d]+M)?([.,\d]+S)?)?$/.test(input))); -function bind(r) { - return r.test.bind(r); -} -const format = { - date: format_date, - time: format_time.bind(undefined, false), - 'date-time': date_time, - duration: DURATION, - uri, - 'uri-reference': bind(URIREF), - 'uri-template': bind(URITEMPLATE), - url: bind(URL_), - email: EMAIL, - hostname: bind(HOSTNAME), - ipv4: bind(IPV4), - ipv6: bind(IPV6), - regex: regex, - uuid: bind(UUID), - 'json-pointer': bind(JSON_POINTER), - 'json-pointer-uri-fragment': bind(JSON_POINTER_URI_FRAGMENT), - 'relative-json-pointer': bind(RELATIVE_JSON_POINTER) -}; -function isLeapYear(year) { - return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); -} -function format_date(str) { - const matches = str.match(DATE); - if (!matches) - return false; - const year = +matches[1]; - const month = +matches[2]; - const day = +matches[3]; - return (month >= 1 && - month <= 12 && - day >= 1 && - day <= (month == 2 && isLeapYear(year) ? 29 : DAYS[month])); -} -function format_time(full, str) { - const matches = str.match(TIME); - if (!matches) - return false; - const hour = +matches[1]; - const minute = +matches[2]; - const second = +matches[3]; - const timeZone = !!matches[5]; - return (((hour <= 23 && minute <= 59 && second <= 59) || - (hour == 23 && minute == 59 && second == 60)) && - (!full || timeZone)); -} -const DATE_TIME_SEPARATOR = /t|\s/i; -function date_time(str) { - const dateTime = str.split(DATE_TIME_SEPARATOR); - return dateTime.length == 2 && format_date(dateTime[0]) && format_time(true, dateTime[1]); -} -const NOT_URI_FRAGMENT = /\/|:/; -const URI_PATTERN = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; -function uri(str) { - return NOT_URI_FRAGMENT.test(str) && URI_PATTERN.test(str); -} -const Z_ANCHOR = /[^\\]\\Z/; -function regex(str) { - if (Z_ANCHOR.test(str)) - return false; - try { - new RegExp(str, 'u'); - return true; - } - catch (e) { - return false; - } -} - -;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/types.js -var OutputFormat; -(function (OutputFormat) { - OutputFormat[OutputFormat["Flag"] = 1] = "Flag"; - OutputFormat[OutputFormat["Basic"] = 2] = "Basic"; - OutputFormat[OutputFormat["Detailed"] = 4] = "Detailed"; -})(OutputFormat || (OutputFormat = {})); - -;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/ucs2-length.js -function ucs2length(s) { - let result = 0; - let length = s.length; - let index = 0; - let charCode; - while (index < length) { - result++; - charCode = s.charCodeAt(index++); - if (charCode >= 0xd800 && charCode <= 0xdbff && index < length) { - charCode = s.charCodeAt(index); - if ((charCode & 0xfc00) == 0xdc00) { - index++; - } - } - } - return result; -} - -;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/validate.js - - - - - -function validate_validate(instance, schema, draft = '2019-09', lookup = dereference(schema), shortCircuit = true, recursiveAnchor = null, instanceLocation = '#', schemaLocation = '#', evaluated = Object.create(null)) { - if (schema === true) { - return { valid: true, errors: [] }; - } - if (schema === false) { - return { - valid: false, - errors: [ - { - instanceLocation, - keyword: 'false', - keywordLocation: instanceLocation, - error: 'False boolean schema.' - } - ] - }; - } - const rawInstanceType = typeof instance; - let instanceType; - switch (rawInstanceType) { - case 'boolean': - case 'number': - case 'string': - instanceType = rawInstanceType; - break; - case 'object': - if (instance === null) { - instanceType = 'null'; - } - else if (Array.isArray(instance)) { - instanceType = 'array'; - } - else { - instanceType = 'object'; - } - break; - default: - throw new Error(`Instances of "${rawInstanceType}" type are not supported.`); - } - const { $ref, $recursiveRef, $recursiveAnchor, type: $type, const: $const, enum: $enum, required: $required, not: $not, anyOf: $anyOf, allOf: $allOf, oneOf: $oneOf, if: $if, then: $then, else: $else, format: $format, properties: $properties, patternProperties: $patternProperties, additionalProperties: $additionalProperties, unevaluatedProperties: $unevaluatedProperties, minProperties: $minProperties, maxProperties: $maxProperties, propertyNames: $propertyNames, dependentRequired: $dependentRequired, dependentSchemas: $dependentSchemas, dependencies: $dependencies, prefixItems: $prefixItems, items: $items, additionalItems: $additionalItems, unevaluatedItems: $unevaluatedItems, contains: $contains, minContains: $minContains, maxContains: $maxContains, minItems: $minItems, maxItems: $maxItems, uniqueItems: $uniqueItems, minimum: $minimum, maximum: $maximum, exclusiveMinimum: $exclusiveMinimum, exclusiveMaximum: $exclusiveMaximum, multipleOf: $multipleOf, minLength: $minLength, maxLength: $maxLength, pattern: $pattern, __absolute_ref__, __absolute_recursive_ref__ } = schema; - const errors = []; - if ($recursiveAnchor === true && recursiveAnchor === null) { - recursiveAnchor = schema; - } - if ($recursiveRef === '#') { - const refSchema = recursiveAnchor === null - ? lookup[__absolute_recursive_ref__] - : recursiveAnchor; - const keywordLocation = `${schemaLocation}/$recursiveRef`; - const result = validate_validate(instance, recursiveAnchor === null ? schema : recursiveAnchor, draft, lookup, shortCircuit, refSchema, instanceLocation, keywordLocation, evaluated); - if (!result.valid) { - errors.push({ - instanceLocation, - keyword: '$recursiveRef', - keywordLocation, - error: 'A subschema had errors.' - }, ...result.errors); - } - } - if ($ref !== undefined) { - const uri = __absolute_ref__ || $ref; - const refSchema = lookup[uri]; - if (refSchema === undefined) { - let message = `Unresolved $ref "${$ref}".`; - if (__absolute_ref__ && __absolute_ref__ !== $ref) { - message += ` Absolute URI "${__absolute_ref__}".`; - } - message += `\nKnown schemas:\n- ${Object.keys(lookup).join('\n- ')}`; - throw new Error(message); - } - const keywordLocation = `${schemaLocation}/$ref`; - const result = validate_validate(instance, refSchema, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, keywordLocation, evaluated); - if (!result.valid) { - errors.push({ - instanceLocation, - keyword: '$ref', - keywordLocation, - error: 'A subschema had errors.' - }, ...result.errors); - } - if (draft === '4' || draft === '7') { - return { valid: errors.length === 0, errors }; - } - } - if (Array.isArray($type)) { - let length = $type.length; - let valid = false; - for (let i = 0; i < length; i++) { - if (instanceType === $type[i] || - ($type[i] === 'integer' && - instanceType === 'number' && - instance % 1 === 0 && - instance === instance)) { - valid = true; - break; - } - } - if (!valid) { - errors.push({ - instanceLocation, - keyword: 'type', - keywordLocation: `${schemaLocation}/type`, - error: `Instance type "${instanceType}" is invalid. Expected "${$type.join('", "')}".` - }); - } - } - else if ($type === 'integer') { - if (instanceType !== 'number' || instance % 1 || instance !== instance) { - errors.push({ - instanceLocation, - keyword: 'type', - keywordLocation: `${schemaLocation}/type`, - error: `Instance type "${instanceType}" is invalid. Expected "${$type}".` - }); - } - } - else if ($type !== undefined && instanceType !== $type) { - errors.push({ - instanceLocation, - keyword: 'type', - keywordLocation: `${schemaLocation}/type`, - error: `Instance type "${instanceType}" is invalid. Expected "${$type}".` - }); - } - if ($const !== undefined) { - if (instanceType === 'object' || instanceType === 'array') { - if (!deepCompareStrict(instance, $const)) { - errors.push({ - instanceLocation, - keyword: 'const', - keywordLocation: `${schemaLocation}/const`, - error: `Instance does not match ${JSON.stringify($const)}.` - }); - } - } - else if (instance !== $const) { - errors.push({ - instanceLocation, - keyword: 'const', - keywordLocation: `${schemaLocation}/const`, - error: `Instance does not match ${JSON.stringify($const)}.` - }); - } - } - if ($enum !== undefined) { - if (instanceType === 'object' || instanceType === 'array') { - if (!$enum.some(value => deepCompareStrict(instance, value))) { - errors.push({ - instanceLocation, - keyword: 'enum', - keywordLocation: `${schemaLocation}/enum`, - error: `Instance does not match any of ${JSON.stringify($enum)}.` - }); - } - } - else if (!$enum.some(value => instance === value)) { - errors.push({ - instanceLocation, - keyword: 'enum', - keywordLocation: `${schemaLocation}/enum`, - error: `Instance does not match any of ${JSON.stringify($enum)}.` - }); - } - } - if ($not !== undefined) { - const keywordLocation = `${schemaLocation}/not`; - const result = validate_validate(instance, $not, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, keywordLocation); - if (result.valid) { - errors.push({ - instanceLocation, - keyword: 'not', - keywordLocation, - error: 'Instance matched "not" schema.' - }); - } - } - let subEvaluateds = []; - if ($anyOf !== undefined) { - const keywordLocation = `${schemaLocation}/anyOf`; - const errorsLength = errors.length; - let anyValid = false; - for (let i = 0; i < $anyOf.length; i++) { - const subSchema = $anyOf[i]; - const subEvaluated = Object.create(evaluated); - const result = validate_validate(instance, subSchema, draft, lookup, shortCircuit, $recursiveAnchor === true ? recursiveAnchor : null, instanceLocation, `${keywordLocation}/${i}`, subEvaluated); - errors.push(...result.errors); - anyValid = anyValid || result.valid; - if (result.valid) { - subEvaluateds.push(subEvaluated); - } - } - if (anyValid) { - errors.length = errorsLength; - } - else { - errors.splice(errorsLength, 0, { - instanceLocation, - keyword: 'anyOf', - keywordLocation, - error: 'Instance does not match any subschemas.' - }); - } - } - if ($allOf !== undefined) { - const keywordLocation = `${schemaLocation}/allOf`; - const errorsLength = errors.length; - let allValid = true; - for (let i = 0; i < $allOf.length; i++) { - const subSchema = $allOf[i]; - const subEvaluated = Object.create(evaluated); - const result = validate_validate(instance, subSchema, draft, lookup, shortCircuit, $recursiveAnchor === true ? recursiveAnchor : null, instanceLocation, `${keywordLocation}/${i}`, subEvaluated); - errors.push(...result.errors); - allValid = allValid && result.valid; - if (result.valid) { - subEvaluateds.push(subEvaluated); - } - } - if (allValid) { - errors.length = errorsLength; - } - else { - errors.splice(errorsLength, 0, { - instanceLocation, - keyword: 'allOf', - keywordLocation, - error: `Instance does not match every subschema.` - }); - } - } - if ($oneOf !== undefined) { - const keywordLocation = `${schemaLocation}/oneOf`; - const errorsLength = errors.length; - const matches = $oneOf.filter((subSchema, i) => { - const subEvaluated = Object.create(evaluated); - const result = validate_validate(instance, subSchema, draft, lookup, shortCircuit, $recursiveAnchor === true ? recursiveAnchor : null, instanceLocation, `${keywordLocation}/${i}`, subEvaluated); - errors.push(...result.errors); - if (result.valid) { - subEvaluateds.push(subEvaluated); - } - return result.valid; - }).length; - if (matches === 1) { - errors.length = errorsLength; - } - else { - errors.splice(errorsLength, 0, { - instanceLocation, - keyword: 'oneOf', - keywordLocation, - error: `Instance does not match exactly one subschema (${matches} matches).` - }); - } - } - if (instanceType === 'object' || instanceType === 'array') { - Object.assign(evaluated, ...subEvaluateds); - } - if ($if !== undefined) { - const keywordLocation = `${schemaLocation}/if`; - const conditionResult = validate_validate(instance, $if, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, keywordLocation, evaluated).valid; - if (conditionResult) { - if ($then !== undefined) { - const thenResult = validate_validate(instance, $then, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, `${schemaLocation}/then`, evaluated); - if (!thenResult.valid) { - errors.push({ - instanceLocation, - keyword: 'if', - keywordLocation, - error: `Instance does not match "then" schema.` - }, ...thenResult.errors); - } - } - } - else if ($else !== undefined) { - const elseResult = validate_validate(instance, $else, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, `${schemaLocation}/else`, evaluated); - if (!elseResult.valid) { - errors.push({ - instanceLocation, - keyword: 'if', - keywordLocation, - error: `Instance does not match "else" schema.` - }, ...elseResult.errors); - } - } - } - if (instanceType === 'object') { - if ($required !== undefined) { - for (const key of $required) { - if (!(key in instance)) { - errors.push({ - instanceLocation, - keyword: 'required', - keywordLocation: `${schemaLocation}/required`, - error: `Instance does not have required property "${key}".` - }); - } - } - } - const keys = Object.keys(instance); - if ($minProperties !== undefined && keys.length < $minProperties) { - errors.push({ - instanceLocation, - keyword: 'minProperties', - keywordLocation: `${schemaLocation}/minProperties`, - error: `Instance does not have at least ${$minProperties} properties.` - }); - } - if ($maxProperties !== undefined && keys.length > $maxProperties) { - errors.push({ - instanceLocation, - keyword: 'maxProperties', - keywordLocation: `${schemaLocation}/maxProperties`, - error: `Instance does not have at least ${$maxProperties} properties.` - }); - } - if ($propertyNames !== undefined) { - const keywordLocation = `${schemaLocation}/propertyNames`; - for (const key in instance) { - const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; - const result = validate_validate(key, $propertyNames, draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, keywordLocation); - if (!result.valid) { - errors.push({ - instanceLocation, - keyword: 'propertyNames', - keywordLocation, - error: `Property name "${key}" does not match schema.` - }, ...result.errors); - } - } - } - if ($dependentRequired !== undefined) { - const keywordLocation = `${schemaLocation}/dependantRequired`; - for (const key in $dependentRequired) { - if (key in instance) { - const required = $dependentRequired[key]; - for (const dependantKey of required) { - if (!(dependantKey in instance)) { - errors.push({ - instanceLocation, - keyword: 'dependentRequired', - keywordLocation, - error: `Instance has "${key}" but does not have "${dependantKey}".` - }); - } - } - } - } - } - if ($dependentSchemas !== undefined) { - for (const key in $dependentSchemas) { - const keywordLocation = `${schemaLocation}/dependentSchemas`; - if (key in instance) { - const result = validate_validate(instance, $dependentSchemas[key], draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, `${keywordLocation}/${encodePointer(key)}`, evaluated); - if (!result.valid) { - errors.push({ - instanceLocation, - keyword: 'dependentSchemas', - keywordLocation, - error: `Instance has "${key}" but does not match dependant schema.` - }, ...result.errors); - } - } - } - } - if ($dependencies !== undefined) { - const keywordLocation = `${schemaLocation}/dependencies`; - for (const key in $dependencies) { - if (key in instance) { - const propsOrSchema = $dependencies[key]; - if (Array.isArray(propsOrSchema)) { - for (const dependantKey of propsOrSchema) { - if (!(dependantKey in instance)) { - errors.push({ - instanceLocation, - keyword: 'dependencies', - keywordLocation, - error: `Instance has "${key}" but does not have "${dependantKey}".` - }); - } - } - } - else { - const result = validate_validate(instance, propsOrSchema, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, `${keywordLocation}/${encodePointer(key)}`); - if (!result.valid) { - errors.push({ - instanceLocation, - keyword: 'dependencies', - keywordLocation, - error: `Instance has "${key}" but does not match dependant schema.` - }, ...result.errors); - } - } - } - } - } - const thisEvaluated = Object.create(null); - let stop = false; - if ($properties !== undefined) { - const keywordLocation = `${schemaLocation}/properties`; - for (const key in $properties) { - if (!(key in instance)) { - continue; - } - const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; - const result = validate_validate(instance[key], $properties[key], draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, `${keywordLocation}/${encodePointer(key)}`); - if (result.valid) { - evaluated[key] = thisEvaluated[key] = true; - } - else { - stop = shortCircuit; - errors.push({ - instanceLocation, - keyword: 'properties', - keywordLocation, - error: `Property "${key}" does not match schema.` - }, ...result.errors); - if (stop) - break; - } - } - } - if (!stop && $patternProperties !== undefined) { - const keywordLocation = `${schemaLocation}/patternProperties`; - for (const pattern in $patternProperties) { - const regex = new RegExp(pattern, 'u'); - const subSchema = $patternProperties[pattern]; - for (const key in instance) { - if (!regex.test(key)) { - continue; - } - const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; - const result = validate_validate(instance[key], subSchema, draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, `${keywordLocation}/${encodePointer(pattern)}`); - if (result.valid) { - evaluated[key] = thisEvaluated[key] = true; - } - else { - stop = shortCircuit; - errors.push({ - instanceLocation, - keyword: 'patternProperties', - keywordLocation, - error: `Property "${key}" matches pattern "${pattern}" but does not match associated schema.` - }, ...result.errors); - } - } - } - } - if (!stop && $additionalProperties !== undefined) { - const keywordLocation = `${schemaLocation}/additionalProperties`; - for (const key in instance) { - if (thisEvaluated[key]) { - continue; - } - const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; - const result = validate_validate(instance[key], $additionalProperties, draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, keywordLocation); - if (result.valid) { - evaluated[key] = true; - } - else { - stop = shortCircuit; - errors.push({ - instanceLocation, - keyword: 'additionalProperties', - keywordLocation, - error: `Property "${key}" does not match additional properties schema.` - }, ...result.errors); - } - } - } - else if (!stop && $unevaluatedProperties !== undefined) { - const keywordLocation = `${schemaLocation}/unevaluatedProperties`; - for (const key in instance) { - if (!evaluated[key]) { - const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; - const result = validate_validate(instance[key], $unevaluatedProperties, draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, keywordLocation); - if (result.valid) { - evaluated[key] = true; - } - else { - errors.push({ - instanceLocation, - keyword: 'unevaluatedProperties', - keywordLocation, - error: `Property "${key}" does not match unevaluated properties schema.` - }, ...result.errors); - } - } - } - } - } - else if (instanceType === 'array') { - if ($maxItems !== undefined && instance.length > $maxItems) { - errors.push({ - instanceLocation, - keyword: 'maxItems', - keywordLocation: `${schemaLocation}/maxItems`, - error: `Array has too many items (${instance.length} > ${$maxItems}).` - }); - } - if ($minItems !== undefined && instance.length < $minItems) { - errors.push({ - instanceLocation, - keyword: 'minItems', - keywordLocation: `${schemaLocation}/minItems`, - error: `Array has too few items (${instance.length} < ${$minItems}).` - }); - } - const length = instance.length; - let i = 0; - let stop = false; - if ($prefixItems !== undefined) { - const keywordLocation = `${schemaLocation}/prefixItems`; - const length2 = Math.min($prefixItems.length, length); - for (; i < length2; i++) { - const result = validate_validate(instance[i], $prefixItems[i], draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, `${keywordLocation}/${i}`); - evaluated[i] = true; - if (!result.valid) { - stop = shortCircuit; - errors.push({ - instanceLocation, - keyword: 'prefixItems', - keywordLocation, - error: `Items did not match schema.` - }, ...result.errors); - if (stop) - break; - } - } - } - if ($items !== undefined) { - const keywordLocation = `${schemaLocation}/items`; - if (Array.isArray($items)) { - const length2 = Math.min($items.length, length); - for (; i < length2; i++) { - const result = validate_validate(instance[i], $items[i], draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, `${keywordLocation}/${i}`); - evaluated[i] = true; - if (!result.valid) { - stop = shortCircuit; - errors.push({ - instanceLocation, - keyword: 'items', - keywordLocation, - error: `Items did not match schema.` - }, ...result.errors); - if (stop) - break; - } - } - } - else { - for (; i < length; i++) { - const result = validate_validate(instance[i], $items, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, keywordLocation); - evaluated[i] = true; - if (!result.valid) { - stop = shortCircuit; - errors.push({ - instanceLocation, - keyword: 'items', - keywordLocation, - error: `Items did not match schema.` - }, ...result.errors); - if (stop) - break; - } - } - } - if (!stop && $additionalItems !== undefined) { - const keywordLocation = `${schemaLocation}/additionalItems`; - for (; i < length; i++) { - const result = validate_validate(instance[i], $additionalItems, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, keywordLocation); - evaluated[i] = true; - if (!result.valid) { - stop = shortCircuit; - errors.push({ - instanceLocation, - keyword: 'additionalItems', - keywordLocation, - error: `Items did not match additional items schema.` - }, ...result.errors); - } - } - } - } - if ($contains !== undefined) { - if (length === 0 && $minContains === undefined) { - errors.push({ - instanceLocation, - keyword: 'contains', - keywordLocation: `${schemaLocation}/contains`, - error: `Array is empty. It must contain at least one item matching the schema.` - }); - } - else if ($minContains !== undefined && length < $minContains) { - errors.push({ - instanceLocation, - keyword: 'minContains', - keywordLocation: `${schemaLocation}/minContains`, - error: `Array has less items (${length}) than minContains (${$minContains}).` - }); - } - else { - const keywordLocation = `${schemaLocation}/contains`; - const errorsLength = errors.length; - let contained = 0; - for (let j = 0; j < length; j++) { - const result = validate_validate(instance[j], $contains, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${j}`, keywordLocation); - if (result.valid) { - evaluated[j] = true; - contained++; - } - else { - errors.push(...result.errors); - } - } - if (contained >= ($minContains || 0)) { - errors.length = errorsLength; - } - if ($minContains === undefined && - $maxContains === undefined && - contained === 0) { - errors.splice(errorsLength, 0, { - instanceLocation, - keyword: 'contains', - keywordLocation, - error: `Array does not contain item matching schema.` - }); - } - else if ($minContains !== undefined && contained < $minContains) { - errors.push({ - instanceLocation, - keyword: 'minContains', - keywordLocation: `${schemaLocation}/minContains`, - error: `Array must contain at least ${$minContains} items matching schema. Only ${contained} items were found.` - }); - } - else if ($maxContains !== undefined && contained > $maxContains) { - errors.push({ - instanceLocation, - keyword: 'maxContains', - keywordLocation: `${schemaLocation}/maxContains`, - error: `Array may contain at most ${$maxContains} items matching schema. ${contained} items were found.` - }); - } - } - } - if (!stop && $unevaluatedItems !== undefined) { - const keywordLocation = `${schemaLocation}/unevaluatedItems`; - for (i; i < length; i++) { - if (evaluated[i]) { - continue; - } - const result = validate_validate(instance[i], $unevaluatedItems, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, keywordLocation); - evaluated[i] = true; - if (!result.valid) { - errors.push({ - instanceLocation, - keyword: 'unevaluatedItems', - keywordLocation, - error: `Items did not match unevaluated items schema.` - }, ...result.errors); - } - } - } - if ($uniqueItems) { - for (let j = 0; j < length; j++) { - const a = instance[j]; - const ao = typeof a === 'object' && a !== null; - for (let k = 0; k < length; k++) { - if (j === k) { - continue; - } - const b = instance[k]; - const bo = typeof b === 'object' && b !== null; - if (a === b || (ao && bo && deepCompareStrict(a, b))) { - errors.push({ - instanceLocation, - keyword: 'uniqueItems', - keywordLocation: `${schemaLocation}/uniqueItems`, - error: `Duplicate items at indexes ${j} and ${k}.` - }); - j = Number.MAX_SAFE_INTEGER; - k = Number.MAX_SAFE_INTEGER; - } - } - } - } - } - else if (instanceType === 'number') { - if (draft === '4') { - if ($minimum !== undefined && - (($exclusiveMinimum === true && instance <= $minimum) || - instance < $minimum)) { - errors.push({ - instanceLocation, - keyword: 'minimum', - keywordLocation: `${schemaLocation}/minimum`, - error: `${instance} is less than ${$exclusiveMinimum ? 'or equal to ' : ''} ${$minimum}.` - }); - } - if ($maximum !== undefined && - (($exclusiveMaximum === true && instance >= $maximum) || - instance > $maximum)) { - errors.push({ - instanceLocation, - keyword: 'maximum', - keywordLocation: `${schemaLocation}/maximum`, - error: `${instance} is greater than ${$exclusiveMaximum ? 'or equal to ' : ''} ${$maximum}.` - }); - } - } - else { - if ($minimum !== undefined && instance < $minimum) { - errors.push({ - instanceLocation, - keyword: 'minimum', - keywordLocation: `${schemaLocation}/minimum`, - error: `${instance} is less than ${$minimum}.` - }); - } - if ($maximum !== undefined && instance > $maximum) { - errors.push({ - instanceLocation, - keyword: 'maximum', - keywordLocation: `${schemaLocation}/maximum`, - error: `${instance} is greater than ${$maximum}.` - }); - } - if ($exclusiveMinimum !== undefined && instance <= $exclusiveMinimum) { - errors.push({ - instanceLocation, - keyword: 'exclusiveMinimum', - keywordLocation: `${schemaLocation}/exclusiveMinimum`, - error: `${instance} is less than ${$exclusiveMinimum}.` - }); - } - if ($exclusiveMaximum !== undefined && instance >= $exclusiveMaximum) { - errors.push({ - instanceLocation, - keyword: 'exclusiveMaximum', - keywordLocation: `${schemaLocation}/exclusiveMaximum`, - error: `${instance} is greater than or equal to ${$exclusiveMaximum}.` - }); - } - } - if ($multipleOf !== undefined) { - const remainder = instance % $multipleOf; - if (Math.abs(0 - remainder) >= 1.1920929e-7 && - Math.abs($multipleOf - remainder) >= 1.1920929e-7) { - errors.push({ - instanceLocation, - keyword: 'multipleOf', - keywordLocation: `${schemaLocation}/multipleOf`, - error: `${instance} is not a multiple of ${$multipleOf}.` - }); - } - } - } - else if (instanceType === 'string') { - const length = $minLength === undefined && $maxLength === undefined - ? 0 - : ucs2length(instance); - if ($minLength !== undefined && length < $minLength) { - errors.push({ - instanceLocation, - keyword: 'minLength', - keywordLocation: `${schemaLocation}/minLength`, - error: `String is too short (${length} < ${$minLength}).` - }); - } - if ($maxLength !== undefined && length > $maxLength) { - errors.push({ - instanceLocation, - keyword: 'maxLength', - keywordLocation: `${schemaLocation}/maxLength`, - error: `String is too long (${length} > ${$maxLength}).` - }); - } - if ($pattern !== undefined && !new RegExp($pattern, 'u').test(instance)) { - errors.push({ - instanceLocation, - keyword: 'pattern', - keywordLocation: `${schemaLocation}/pattern`, - error: `String does not match pattern.` - }); - } - if ($format !== undefined && - format[$format] && - !format[$format](instance)) { - errors.push({ - instanceLocation, - keyword: 'format', - keywordLocation: `${schemaLocation}/format`, - error: `String does not match format "${$format}".` - }); - } - } - return { valid: errors.length === 0, errors }; -} - -;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/validator.js - - -class Validator { - schema; - draft; - shortCircuit; - lookup; - constructor(schema, draft = '2019-09', shortCircuit = true) { - this.schema = schema; - this.draft = draft; - this.shortCircuit = shortCircuit; - this.lookup = dereference(schema); - } - validate(instance) { - return validate_validate(instance, this.schema, this.draft, this.lookup, this.shortCircuit); - } - addSchema(schema, id) { - if (id) { - schema = { ...schema, $id: id }; - } - dereference(schema, this.lookup); - } -} - -;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/index.js - - - - - - - - - -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/json_schema.js - - - - - - - -//#region src/utils/json_schema.ts -var json_schema_exports = {}; -__export(json_schema_exports, { - Validator: () => Validator, - deepCompareStrict: () => deepCompareStrict, - toJsonSchema: () => toJsonSchema, - validatesOnlyStrings: () => validatesOnlyStrings -}); -/** -* Converts a Zod schema or JSON schema to a JSON schema. -* @param schema - The schema to convert. -* @returns The converted schema. -*/ -function toJsonSchema(schema) { - if (isZodSchemaV4(schema)) { - const inputSchema = interopZodTransformInputSchema(schema, true); - if (isZodObjectV4(inputSchema)) { - const strictSchema = interopZodObjectStrict(inputSchema, true); - return toJSONSchema(strictSchema); - } else return toJSONSchema(schema); - } - if (isZodSchemaV3(schema)) return zodToJsonSchema_zodToJsonSchema(schema); - return schema; -} -/** -* Validates if a JSON schema validates only strings. May return false negatives in some edge cases -* (like recursive or unresolvable refs). -* -* @param schema - The schema to validate. -* @returns `true` if the schema validates only strings, `false` otherwise. -*/ -function validatesOnlyStrings(schema) { - if (!schema || typeof schema !== "object" || Object.keys(schema).length === 0 || Array.isArray(schema)) return false; - if ("type" in schema) { - if (typeof schema.type === "string") return schema.type === "string"; - if (Array.isArray(schema.type)) return schema.type.every((t) => t === "string"); - return false; - } - if ("enum" in schema) return Array.isArray(schema.enum) && schema.enum.length > 0 && schema.enum.every((val) => typeof val === "string"); - if ("const" in schema) return typeof schema.const === "string"; - if ("allOf" in schema && Array.isArray(schema.allOf)) return schema.allOf.some((subschema) => validatesOnlyStrings(subschema)); - if ("anyOf" in schema && Array.isArray(schema.anyOf) || "oneOf" in schema && Array.isArray(schema.oneOf)) { - const subschemas = "anyOf" in schema ? schema.anyOf : schema.oneOf; - return subschemas.length > 0 && subschemas.every((subschema) => validatesOnlyStrings(subschema)); - } - if ("not" in schema) return false; - if ("$ref" in schema && typeof schema.$ref === "string") { - const ref = schema.$ref; - const resolved = dereference(schema); - if (resolved[ref]) return validatesOnlyStrings(resolved[ref]); - return false; - } - return false; -} - -//#endregion - -//# sourceMappingURL=json_schema.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/utils.js -//#region src/runnables/utils.ts -function isRunnableInterface(thing) { - return thing ? thing.lc_runnable : false; -} -/** -* Utility to filter the root event in the streamEvents implementation. -* This is simply binding the arguments to the namespace to make save on -* a bit of typing in the streamEvents implementation. -* -* TODO: Refactor and remove. -*/ -var _RootEventFilter = class { - includeNames; - includeTypes; - includeTags; - excludeNames; - excludeTypes; - excludeTags; - constructor(fields) { - this.includeNames = fields.includeNames; - this.includeTypes = fields.includeTypes; - this.includeTags = fields.includeTags; - this.excludeNames = fields.excludeNames; - this.excludeTypes = fields.excludeTypes; - this.excludeTags = fields.excludeTags; - } - includeEvent(event, rootType) { - let include = this.includeNames === void 0 && this.includeTypes === void 0 && this.includeTags === void 0; - const eventTags = event.tags ?? []; - if (this.includeNames !== void 0) include = include || this.includeNames.includes(event.name); - if (this.includeTypes !== void 0) include = include || this.includeTypes.includes(rootType); - if (this.includeTags !== void 0) include = include || eventTags.some((tag) => this.includeTags?.includes(tag)); - if (this.excludeNames !== void 0) include = include && !this.excludeNames.includes(event.name); - if (this.excludeTypes !== void 0) include = include && !this.excludeTypes.includes(rootType); - if (this.excludeTags !== void 0) include = include && eventTags.every((tag) => !this.excludeTags?.includes(tag)); - return include; - } -}; - -//#endregion - -//# sourceMappingURL=utils.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/graph_mermaid.js -//#region src/runnables/graph_mermaid.ts -function _escapeNodeLabel(nodeLabel) { - return nodeLabel.replace(/[^a-zA-Z-_0-9]/g, "_"); -} -const MARKDOWN_SPECIAL_CHARS = [ - "*", - "_", - "`" -]; -function _generateMermaidGraphStyles(nodeColors) { - let styles = ""; - for (const [className, color] of Object.entries(nodeColors)) styles += `\tclassDef ${className} ${color};\n`; - return styles; -} -/** -* Draws a Mermaid graph using the provided graph data -*/ -function drawMermaid(nodes, edges, config) { - const { firstNode, lastNode, nodeColors, withStyles = true, curveStyle = "linear", wrapLabelNWords = 9 } = config ?? {}; - let mermaidGraph = withStyles ? `%%{init: {'flowchart': {'curve': '${curveStyle}'}}}%%\ngraph TD;\n` : "graph TD;\n"; - if (withStyles) { - const defaultClassLabel = "default"; - const formatDict = { [defaultClassLabel]: "{0}({1})" }; - if (firstNode !== void 0) formatDict[firstNode] = "{0}([{1}]):::first"; - if (lastNode !== void 0) formatDict[lastNode] = "{0}([{1}]):::last"; - for (const [key, node] of Object.entries(nodes)) { - const nodeName = node.name.split(":").pop() ?? ""; - const label = MARKDOWN_SPECIAL_CHARS.some((char) => nodeName.startsWith(char) && nodeName.endsWith(char)) ? `

${nodeName}

` : nodeName; - let finalLabel = label; - if (Object.keys(node.metadata ?? {}).length) finalLabel += `
${Object.entries(node.metadata ?? {}).map(([k, v]) => `${k} = ${v}`).join("\n")}`; - const nodeLabel = (formatDict[key] ?? formatDict[defaultClassLabel]).replace("{0}", _escapeNodeLabel(key)).replace("{1}", finalLabel); - mermaidGraph += `\t${nodeLabel}\n`; - } - } - const edgeGroups = {}; - for (const edge of edges) { - const srcParts = edge.source.split(":"); - const tgtParts = edge.target.split(":"); - const commonPrefix = srcParts.filter((src, i) => src === tgtParts[i]).join(":"); - if (!edgeGroups[commonPrefix]) edgeGroups[commonPrefix] = []; - edgeGroups[commonPrefix].push(edge); - } - const seenSubgraphs = /* @__PURE__ */ new Set(); - function addSubgraph(edges$1, prefix) { - const selfLoop = edges$1.length === 1 && edges$1[0].source === edges$1[0].target; - if (prefix && !selfLoop) { - const subgraph = prefix.split(":").pop(); - if (seenSubgraphs.has(subgraph)) throw new Error(`Found duplicate subgraph '${subgraph}' -- this likely means that you're reusing a subgraph node with the same name. Please adjust your graph to have subgraph nodes with unique names.`); - seenSubgraphs.add(subgraph); - mermaidGraph += `\tsubgraph ${subgraph}\n`; - } - for (const edge of edges$1) { - const { source, target, data, conditional } = edge; - let edgeLabel = ""; - if (data !== void 0) { - let edgeData = data; - const words = edgeData.split(" "); - if (words.length > wrapLabelNWords) edgeData = Array.from({ length: Math.ceil(words.length / wrapLabelNWords) }, (_, i) => words.slice(i * wrapLabelNWords, (i + 1) * wrapLabelNWords).join(" ")).join(" 
 "); - edgeLabel = conditional ? ` -.  ${edgeData}  .-> ` : ` --  ${edgeData}  --> `; - } else edgeLabel = conditional ? " -.-> " : " --> "; - mermaidGraph += `\t${_escapeNodeLabel(source)}${edgeLabel}${_escapeNodeLabel(target)};\n`; - } - for (const nestedPrefix in edgeGroups) if (nestedPrefix.startsWith(`${prefix}:`) && nestedPrefix !== prefix) addSubgraph(edgeGroups[nestedPrefix], nestedPrefix); - if (prefix && !selfLoop) mermaidGraph += " end\n"; - } - addSubgraph(edgeGroups[""] ?? [], ""); - for (const prefix in edgeGroups) if (!prefix.includes(":") && prefix !== "") addSubgraph(edgeGroups[prefix], prefix); - if (withStyles) mermaidGraph += _generateMermaidGraphStyles(nodeColors ?? {}); - return mermaidGraph; -} -/** -* Renders Mermaid graph using the Mermaid.INK API. -* -* @example -* ```javascript -* const image = await drawMermaidImage(mermaidSyntax, { -* backgroundColor: "white", -* imageType: "png", -* }); -* fs.writeFileSync("image.png", image); -* ``` -* -* @param mermaidSyntax - The Mermaid syntax to render. -* @param config - The configuration for the image. -* @returns The image as a Blob. -*/ -async function drawMermaidImage(mermaidSyntax, config) { - let backgroundColor = config?.backgroundColor ?? "white"; - const imageType = config?.imageType ?? "png"; - const mermaidSyntaxEncoded = btoa(mermaidSyntax); - if (backgroundColor !== void 0) { - const hexColorPattern = /^#(?:[0-9a-fA-F]{3}){1,2}$/; - if (!hexColorPattern.test(backgroundColor)) backgroundColor = `!${backgroundColor}`; - } - const imageUrl = `https://mermaid.ink/img/${mermaidSyntaxEncoded}?bgColor=${backgroundColor}&type=${imageType}`; - const res = await fetch(imageUrl); - if (!res.ok) throw new Error([ - `Failed to render the graph using the Mermaid.INK API.`, - `Status code: ${res.status}`, - `Status text: ${res.statusText}` - ].join("\n")); - const content = await res.blob(); - return content; -} - -//#endregion - -//# sourceMappingURL=graph_mermaid.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/graph.js - - - - - - -//#region src/runnables/graph.ts -var graph_exports = {}; -__export(graph_exports, { Graph: () => Graph }); -function nodeDataStr(id, data) { - if (id !== void 0 && !wrapper_validate(id)) return id; - else if (isRunnableInterface(data)) try { - let dataStr = data.getName(); - dataStr = dataStr.startsWith("Runnable") ? dataStr.slice(8) : dataStr; - return dataStr; - } catch { - return data.getName(); - } - else return data.name ?? "UnknownSchema"; -} -function nodeDataJson(node) { - if (isRunnableInterface(node.data)) return { - type: "runnable", - data: { - id: node.data.lc_id, - name: node.data.getName() - } - }; - else return { - type: "schema", - data: { - ...toJsonSchema(node.data.schema), - title: node.data.name - } - }; -} -var Graph = class Graph { - nodes = {}; - edges = []; - constructor(params) { - this.nodes = params?.nodes ?? this.nodes; - this.edges = params?.edges ?? this.edges; - } - toJSON() { - const stableNodeIds = {}; - Object.values(this.nodes).forEach((node, i) => { - stableNodeIds[node.id] = wrapper_validate(node.id) ? i : node.id; - }); - return { - nodes: Object.values(this.nodes).map((node) => ({ - id: stableNodeIds[node.id], - ...nodeDataJson(node) - })), - edges: this.edges.map((edge) => { - const item = { - source: stableNodeIds[edge.source], - target: stableNodeIds[edge.target] - }; - if (typeof edge.data !== "undefined") item.data = edge.data; - if (typeof edge.conditional !== "undefined") item.conditional = edge.conditional; - return item; - }) - }; - } - addNode(data, id, metadata) { - if (id !== void 0 && this.nodes[id] !== void 0) throw new Error(`Node with id ${id} already exists`); - const nodeId = id ?? v4(); - const node = { - id: nodeId, - data, - name: nodeDataStr(id, data), - metadata - }; - this.nodes[nodeId] = node; - return node; - } - removeNode(node) { - delete this.nodes[node.id]; - this.edges = this.edges.filter((edge) => edge.source !== node.id && edge.target !== node.id); - } - addEdge(source, target, data, conditional) { - if (this.nodes[source.id] === void 0) throw new Error(`Source node ${source.id} not in graph`); - if (this.nodes[target.id] === void 0) throw new Error(`Target node ${target.id} not in graph`); - const edge = { - source: source.id, - target: target.id, - data, - conditional - }; - this.edges.push(edge); - return edge; - } - firstNode() { - return _firstNode(this); - } - lastNode() { - return _lastNode(this); - } - /** - * Add all nodes and edges from another graph. - * Note this doesn't check for duplicates, nor does it connect the graphs. - */ - extend(graph, prefix = "") { - let finalPrefix = prefix; - const nodeIds = Object.values(graph.nodes).map((node) => node.id); - if (nodeIds.every(wrapper_validate)) finalPrefix = ""; - const prefixed = (id) => { - return finalPrefix ? `${finalPrefix}:${id}` : id; - }; - Object.entries(graph.nodes).forEach(([key, value]) => { - this.nodes[prefixed(key)] = { - ...value, - id: prefixed(key) - }; - }); - const newEdges = graph.edges.map((edge) => { - return { - ...edge, - source: prefixed(edge.source), - target: prefixed(edge.target) - }; - }); - this.edges = [...this.edges, ...newEdges]; - const first = graph.firstNode(); - const last = graph.lastNode(); - return [first ? { - id: prefixed(first.id), - data: first.data - } : void 0, last ? { - id: prefixed(last.id), - data: last.data - } : void 0]; - } - trimFirstNode() { - const firstNode = this.firstNode(); - if (firstNode && _firstNode(this, [firstNode.id])) this.removeNode(firstNode); - } - trimLastNode() { - const lastNode = this.lastNode(); - if (lastNode && _lastNode(this, [lastNode.id])) this.removeNode(lastNode); - } - /** - * Return a new graph with all nodes re-identified, - * using their unique, readable names where possible. - */ - reid() { - const nodeLabels = Object.fromEntries(Object.values(this.nodes).map((node) => [node.id, node.name])); - const nodeLabelCounts = /* @__PURE__ */ new Map(); - Object.values(nodeLabels).forEach((label) => { - nodeLabelCounts.set(label, (nodeLabelCounts.get(label) || 0) + 1); - }); - const getNodeId = (nodeId) => { - const label = nodeLabels[nodeId]; - if (wrapper_validate(nodeId) && nodeLabelCounts.get(label) === 1) return label; - else return nodeId; - }; - return new Graph({ - nodes: Object.fromEntries(Object.entries(this.nodes).map(([id, node]) => [getNodeId(id), { - ...node, - id: getNodeId(id) - }])), - edges: this.edges.map((edge) => ({ - ...edge, - source: getNodeId(edge.source), - target: getNodeId(edge.target) - })) - }); - } - drawMermaid(params) { - const { withStyles, curveStyle, nodeColors = { - default: "fill:#f2f0ff,line-height:1.2", - first: "fill-opacity:0", - last: "fill:#bfb6fc" - }, wrapLabelNWords } = params ?? {}; - const graph = this.reid(); - const firstNode = graph.firstNode(); - const lastNode = graph.lastNode(); - return drawMermaid(graph.nodes, graph.edges, { - firstNode: firstNode?.id, - lastNode: lastNode?.id, - withStyles, - curveStyle, - nodeColors, - wrapLabelNWords - }); - } - async drawMermaidPng(params) { - const mermaidSyntax = this.drawMermaid(params); - return drawMermaidImage(mermaidSyntax, { backgroundColor: params?.backgroundColor }); - } -}; -/** -* Find the single node that is not a target of any edge. -* Exclude nodes/sources with ids in the exclude list. -* If there is no such node, or there are multiple, return undefined. -* When drawing the graph, this node would be the origin. -*/ -function _firstNode(graph, exclude = []) { - const targets = new Set(graph.edges.filter((edge) => !exclude.includes(edge.source)).map((edge) => edge.target)); - const found = []; - for (const node of Object.values(graph.nodes)) if (!exclude.includes(node.id) && !targets.has(node.id)) found.push(node); - return found.length === 1 ? found[0] : void 0; -} -/** -* Find the single node that is not a source of any edge. -* Exclude nodes/targets with ids in the exclude list. -* If there is no such node, or there are multiple, return undefined. -* When drawing the graph, this node would be the destination. -*/ -function _lastNode(graph, exclude = []) { - const sources = new Set(graph.edges.filter((edge) => !exclude.includes(edge.target)).map((edge) => edge.source)); - const found = []; - for (const node of Object.values(graph.nodes)) if (!exclude.includes(node.id) && !sources.has(node.id)) found.push(node); - return found.length === 1 ? found[0] : void 0; -} - -//#endregion - -//# sourceMappingURL=graph.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tracers/event_stream.js - - - - - -//#region src/tracers/event_stream.ts -function assignName({ name, serialized }) { - if (name !== void 0) return name; - if (serialized?.name !== void 0) return serialized.name; - else if (serialized?.id !== void 0 && Array.isArray(serialized?.id)) return serialized.id[serialized.id.length - 1]; - return "Unnamed"; -} -const isStreamEventsHandler = (handler) => handler.name === "event_stream_tracer"; -/** -* Class that extends the `BaseTracer` class from the -* `langchain.callbacks.tracers.base` module. It represents a callback -* handler that logs the execution of runs and emits `RunLog` instances to a -* `RunLogStream`. -*/ -var EventStreamCallbackHandler = class extends BaseTracer { - autoClose = true; - includeNames; - includeTypes; - includeTags; - excludeNames; - excludeTypes; - excludeTags; - runInfoMap = /* @__PURE__ */ new Map(); - tappedPromises = /* @__PURE__ */ new Map(); - transformStream; - writer; - receiveStream; - name = "event_stream_tracer"; - lc_prefer_streaming = true; - constructor(fields) { - super({ - _awaitHandler: true, - ...fields - }); - this.autoClose = fields?.autoClose ?? true; - this.includeNames = fields?.includeNames; - this.includeTypes = fields?.includeTypes; - this.includeTags = fields?.includeTags; - this.excludeNames = fields?.excludeNames; - this.excludeTypes = fields?.excludeTypes; - this.excludeTags = fields?.excludeTags; - this.transformStream = new TransformStream(); - this.writer = this.transformStream.writable.getWriter(); - this.receiveStream = IterableReadableStream.fromReadableStream(this.transformStream.readable); - } - [Symbol.asyncIterator]() { - return this.receiveStream; - } - async persistRun(_run) {} - _includeRun(run) { - const runTags = run.tags ?? []; - let include = this.includeNames === void 0 && this.includeTags === void 0 && this.includeTypes === void 0; - if (this.includeNames !== void 0) include = include || this.includeNames.includes(run.name); - if (this.includeTypes !== void 0) include = include || this.includeTypes.includes(run.runType); - if (this.includeTags !== void 0) include = include || runTags.find((tag) => this.includeTags?.includes(tag)) !== void 0; - if (this.excludeNames !== void 0) include = include && !this.excludeNames.includes(run.name); - if (this.excludeTypes !== void 0) include = include && !this.excludeTypes.includes(run.runType); - if (this.excludeTags !== void 0) include = include && runTags.every((tag) => !this.excludeTags?.includes(tag)); - return include; - } - async *tapOutputIterable(runId, outputStream) { - const firstChunk = await outputStream.next(); - if (firstChunk.done) return; - const runInfo = this.runInfoMap.get(runId); - if (runInfo === void 0) { - yield firstChunk.value; - return; - } - function _formatOutputChunk(eventType, data) { - if (eventType === "llm" && typeof data === "string") return new GenerationChunk({ text: data }); - return data; - } - let tappedPromise = this.tappedPromises.get(runId); - if (tappedPromise === void 0) { - let tappedPromiseResolver; - tappedPromise = new Promise((resolve) => { - tappedPromiseResolver = resolve; - }); - this.tappedPromises.set(runId, tappedPromise); - try { - const event = { - event: `on_${runInfo.runType}_stream`, - run_id: runId, - name: runInfo.name, - tags: runInfo.tags, - metadata: runInfo.metadata, - data: {} - }; - await this.send({ - ...event, - data: { chunk: _formatOutputChunk(runInfo.runType, firstChunk.value) } - }, runInfo); - yield firstChunk.value; - for await (const chunk of outputStream) { - if (runInfo.runType !== "tool" && runInfo.runType !== "retriever") await this.send({ - ...event, - data: { chunk: _formatOutputChunk(runInfo.runType, chunk) } - }, runInfo); - yield chunk; - } - } finally { - tappedPromiseResolver?.(); - } - } else { - yield firstChunk.value; - for await (const chunk of outputStream) yield chunk; - } - } - async send(payload, run) { - if (this._includeRun(run)) await this.writer.write(payload); - } - async sendEndEvent(payload, run) { - const tappedPromise = this.tappedPromises.get(payload.run_id); - if (tappedPromise !== void 0) tappedPromise.then(() => { - this.send(payload, run); - }); - else await this.send(payload, run); - } - async onLLMStart(run) { - const runName = assignName(run); - const runType = run.inputs.messages !== void 0 ? "chat_model" : "llm"; - const runInfo = { - tags: run.tags ?? [], - metadata: run.extra?.metadata ?? {}, - name: runName, - runType, - inputs: run.inputs - }; - this.runInfoMap.set(run.id, runInfo); - const eventName = `on_${runType}_start`; - await this.send({ - event: eventName, - data: { input: run.inputs }, - name: runName, - tags: run.tags ?? [], - run_id: run.id, - metadata: run.extra?.metadata ?? {} - }, runInfo); - } - async onLLMNewToken(run, token, kwargs) { - const runInfo = this.runInfoMap.get(run.id); - let chunk; - let eventName; - if (runInfo === void 0) throw new Error(`onLLMNewToken: Run ID ${run.id} not found in run map.`); - if (this.runInfoMap.size === 1) return; - if (runInfo.runType === "chat_model") { - eventName = "on_chat_model_stream"; - if (kwargs?.chunk === void 0) chunk = new AIMessageChunk({ - content: token, - id: `run-${run.id}` - }); - else chunk = kwargs.chunk.message; - } else if (runInfo.runType === "llm") { - eventName = "on_llm_stream"; - if (kwargs?.chunk === void 0) chunk = new GenerationChunk({ text: token }); - else chunk = kwargs.chunk; - } else throw new Error(`Unexpected run type ${runInfo.runType}`); - await this.send({ - event: eventName, - data: { chunk }, - run_id: run.id, - name: runInfo.name, - tags: runInfo.tags, - metadata: runInfo.metadata - }, runInfo); - } - async onLLMEnd(run) { - const runInfo = this.runInfoMap.get(run.id); - this.runInfoMap.delete(run.id); - let eventName; - if (runInfo === void 0) throw new Error(`onLLMEnd: Run ID ${run.id} not found in run map.`); - const generations = run.outputs?.generations; - let output; - if (runInfo.runType === "chat_model") { - for (const generation of generations ?? []) { - if (output !== void 0) break; - output = generation[0]?.message; - } - eventName = "on_chat_model_end"; - } else if (runInfo.runType === "llm") { - output = { - generations: generations?.map((generation) => { - return generation.map((chunk) => { - return { - text: chunk.text, - generationInfo: chunk.generationInfo - }; - }); - }), - llmOutput: run.outputs?.llmOutput ?? {} - }; - eventName = "on_llm_end"; - } else throw new Error(`onLLMEnd: Unexpected run type: ${runInfo.runType}`); - await this.sendEndEvent({ - event: eventName, - data: { - output, - input: runInfo.inputs - }, - run_id: run.id, - name: runInfo.name, - tags: runInfo.tags, - metadata: runInfo.metadata - }, runInfo); - } - async onChainStart(run) { - const runName = assignName(run); - const runType = run.run_type ?? "chain"; - const runInfo = { - tags: run.tags ?? [], - metadata: run.extra?.metadata ?? {}, - name: runName, - runType: run.run_type - }; - let eventData = {}; - if (run.inputs.input === "" && Object.keys(run.inputs).length === 1) { - eventData = {}; - runInfo.inputs = {}; - } else if (run.inputs.input !== void 0) { - eventData.input = run.inputs.input; - runInfo.inputs = run.inputs.input; - } else { - eventData.input = run.inputs; - runInfo.inputs = run.inputs; - } - this.runInfoMap.set(run.id, runInfo); - await this.send({ - event: `on_${runType}_start`, - data: eventData, - name: runName, - tags: run.tags ?? [], - run_id: run.id, - metadata: run.extra?.metadata ?? {} - }, runInfo); - } - async onChainEnd(run) { - const runInfo = this.runInfoMap.get(run.id); - this.runInfoMap.delete(run.id); - if (runInfo === void 0) throw new Error(`onChainEnd: Run ID ${run.id} not found in run map.`); - const eventName = `on_${run.run_type}_end`; - const inputs = run.inputs ?? runInfo.inputs ?? {}; - const outputs = run.outputs?.output ?? run.outputs; - const data = { - output: outputs, - input: inputs - }; - if (inputs.input && Object.keys(inputs).length === 1) { - data.input = inputs.input; - runInfo.inputs = inputs.input; - } - await this.sendEndEvent({ - event: eventName, - data, - run_id: run.id, - name: runInfo.name, - tags: runInfo.tags, - metadata: runInfo.metadata ?? {} - }, runInfo); - } - async onToolStart(run) { - const runName = assignName(run); - const runInfo = { - tags: run.tags ?? [], - metadata: run.extra?.metadata ?? {}, - name: runName, - runType: "tool", - inputs: run.inputs ?? {} - }; - this.runInfoMap.set(run.id, runInfo); - await this.send({ - event: "on_tool_start", - data: { input: run.inputs ?? {} }, - name: runName, - run_id: run.id, - tags: run.tags ?? [], - metadata: run.extra?.metadata ?? {} - }, runInfo); - } - async onToolEnd(run) { - const runInfo = this.runInfoMap.get(run.id); - this.runInfoMap.delete(run.id); - if (runInfo === void 0) throw new Error(`onToolEnd: Run ID ${run.id} not found in run map.`); - if (runInfo.inputs === void 0) throw new Error(`onToolEnd: Run ID ${run.id} is a tool call, and is expected to have traced inputs.`); - const output = run.outputs?.output === void 0 ? run.outputs : run.outputs.output; - await this.sendEndEvent({ - event: "on_tool_end", - data: { - output, - input: runInfo.inputs - }, - run_id: run.id, - name: runInfo.name, - tags: runInfo.tags, - metadata: runInfo.metadata - }, runInfo); - } - async onRetrieverStart(run) { - const runName = assignName(run); - const runType = "retriever"; - const runInfo = { - tags: run.tags ?? [], - metadata: run.extra?.metadata ?? {}, - name: runName, - runType, - inputs: { query: run.inputs.query } - }; - this.runInfoMap.set(run.id, runInfo); - await this.send({ - event: "on_retriever_start", - data: { input: { query: run.inputs.query } }, - name: runName, - tags: run.tags ?? [], - run_id: run.id, - metadata: run.extra?.metadata ?? {} - }, runInfo); - } - async onRetrieverEnd(run) { - const runInfo = this.runInfoMap.get(run.id); - this.runInfoMap.delete(run.id); - if (runInfo === void 0) throw new Error(`onRetrieverEnd: Run ID ${run.id} not found in run map.`); - await this.sendEndEvent({ - event: "on_retriever_end", - data: { - output: run.outputs?.documents ?? run.outputs, - input: runInfo.inputs - }, - run_id: run.id, - name: runInfo.name, - tags: runInfo.tags, - metadata: runInfo.metadata - }, runInfo); - } - async handleCustomEvent(eventName, data, runId) { - const runInfo = this.runInfoMap.get(runId); - if (runInfo === void 0) throw new Error(`handleCustomEvent: Run ID ${runId} not found in run map.`); - await this.send({ - event: "on_custom_event", - run_id: runId, - name: eventName, - tags: runInfo.tags, - metadata: runInfo.metadata, - data - }, runInfo); - } - async finish() { - const pendingPromises = [...this.tappedPromises.values()]; - Promise.all(pendingPromises).finally(() => { - this.writer.close(); - }); - } -}; - -//#endregion - -//# sourceMappingURL=event_stream.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tracers/root_listener.js - - -//#region src/tracers/root_listener.ts -var RootListenersTracer = class extends BaseTracer { - name = "RootListenersTracer"; - /** The Run's ID. Type UUID */ - rootId; - config; - argOnStart; - argOnEnd; - argOnError; - constructor({ config, onStart, onEnd, onError }) { - super({ _awaitHandler: true }); - this.config = config; - this.argOnStart = onStart; - this.argOnEnd = onEnd; - this.argOnError = onError; - } - /** - * This is a legacy method only called once for an entire run tree - * therefore not useful here - * @param {Run} _ Not used - */ - persistRun(_) { - return Promise.resolve(); - } - async onRunCreate(run) { - if (this.rootId) return; - this.rootId = run.id; - if (this.argOnStart) await this.argOnStart(run, this.config); - } - async onRunUpdate(run) { - if (run.id !== this.rootId) return; - if (!run.error) { - if (this.argOnEnd) await this.argOnEnd(run, this.config); - } else if (this.argOnError) await this.argOnError(run, this.config); - } -}; - -//#endregion - -//# sourceMappingURL=root_listener.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/wrappers.js - - -//#region src/runnables/wrappers.ts -function convertToHttpEventStream(stream) { - const encoder = new TextEncoder(); - const finalStream = new ReadableStream({ async start(controller) { - for await (const chunk of stream) controller.enqueue(encoder.encode(`event: data\ndata: ${JSON.stringify(chunk)}\n\n`)); - controller.enqueue(encoder.encode("event: end\n\n")); - controller.close(); - } }); - return IterableReadableStream.fromReadableStream(finalStream); -} - -//#endregion - -//# sourceMappingURL=wrappers.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/iter.js - - - - -//#region src/runnables/iter.ts -function isIterableIterator(thing) { - return typeof thing === "object" && thing !== null && typeof thing[Symbol.iterator] === "function" && typeof thing.next === "function"; -} -const isIterator = (x) => x != null && typeof x === "object" && "next" in x && typeof x.next === "function"; -function isAsyncIterable(thing) { - return typeof thing === "object" && thing !== null && typeof thing[Symbol.asyncIterator] === "function"; -} -function* consumeIteratorInContext(context, iter) { - while (true) { - const { value, done } = async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(context), iter.next.bind(iter), true); - if (done) break; - else yield value; - } +//#region src/utils/types/zod.ts +function isZodSchemaV4(schema) { + if (typeof schema !== "object" || schema === null) return false; + const obj = schema; + if (!("_zod" in obj)) return false; + const zod = obj._zod; + return typeof zod === "object" && zod !== null && "def" in zod; } -async function* consumeAsyncIterableInContext(context, iter) { - const iterator = iter[Symbol.asyncIterator](); - while (true) { - const { value, done } = await async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(context), iterator.next.bind(iter), true); - if (done) break; - else yield value; - } +function isZodSchemaV3(schema) { + if (typeof schema !== "object" || schema === null) return false; + const obj = schema; + if (!("_def" in obj) || "_zod" in obj) return false; + const def = obj._def; + return typeof def === "object" && def != null && "typeName" in def; } - -//#endregion - -//# sourceMappingURL=iter.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/base.js - - - - - - - - - - - - - - - - - - - - - -//#region src/runnables/base.ts -function base_coerceToDict(value, defaultKey) { - return value && !Array.isArray(value) && !(value instanceof Date) && typeof value === "object" ? value : { [defaultKey]: value }; +/** Backward compatible isZodSchema for Zod 3 */ +function isZodSchema(schema) { + if (isZodSchemaV4(schema)) console.warn("[WARNING] Attempting to use Zod 4 schema in a context where Zod 3 schema is expected. This may cause unexpected behavior."); + return isZodSchemaV3(schema); } /** -* A Runnable is a generic unit of work that can be invoked, batched, streamed, and/or -* transformed. +* Given either a Zod schema, or plain object, determine if the input is a Zod schema. +* +* @param {unknown} input +* @returns {boolean} Whether or not the provided input is a Zod schema. */ -var Runnable = class extends Serializable { - lc_runnable = true; - name; - getName(suffix) { - const name = this.name ?? this.constructor.lc_name() ?? this.constructor.name; - return suffix ? `${name}${suffix}` : name; - } - /** - * Add retry logic to an existing runnable. - * @param fields.stopAfterAttempt The number of attempts to retry. - * @param fields.onFailedAttempt A function that is called when a retry fails. - * @returns A new RunnableRetry that, when invoked, will retry according to the parameters. - */ - withRetry(fields) { - return new RunnableRetry({ - bound: this, - kwargs: {}, - config: {}, - maxAttemptNumber: fields?.stopAfterAttempt, - ...fields - }); - } - /** - * Bind config to a Runnable, returning a new Runnable. - * @param config New configuration parameters to attach to the new runnable. - * @returns A new RunnableBinding with a config matching what's passed. - */ - withConfig(config) { - return new RunnableBinding({ - bound: this, - config, - kwargs: {} - }); - } - /** - * Create a new runnable from the current one that will try invoking - * other passed fallback runnables if the initial invocation fails. - * @param fields.fallbacks Other runnables to call if the runnable errors. - * @returns A new RunnableWithFallbacks. - */ - withFallbacks(fields) { - const fallbacks = Array.isArray(fields) ? fields : fields.fallbacks; - return new RunnableWithFallbacks({ - runnable: this, - fallbacks - }); - } - _getOptionsList(options, length = 0) { - if (Array.isArray(options) && options.length !== length) throw new Error(`Passed "options" must be an array with the same length as the inputs, but got ${options.length} options for ${length} inputs`); - if (Array.isArray(options)) return options.map(ensureConfig); - if (length > 1 && !Array.isArray(options) && options.runId) { - console.warn("Provided runId will be used only for the first element of the batch."); - const subsequent = Object.fromEntries(Object.entries(options).filter(([key]) => key !== "runId")); - return Array.from({ length }, (_, i) => ensureConfig(i === 0 ? options : subsequent)); - } - return Array.from({ length }, () => ensureConfig(options)); - } - async batch(inputs, options, batchOptions) { - const configList = this._getOptionsList(options ?? {}, inputs.length); - const maxConcurrency = configList[0]?.maxConcurrency ?? batchOptions?.maxConcurrency; - const caller = new async_caller_AsyncCaller({ - maxConcurrency, - onFailedAttempt: (e) => { - throw e; - } - }); - const batchCalls = inputs.map((input, i) => caller.call(async () => { - try { - const result = await this.invoke(input, configList[i]); - return result; - } catch (e) { - if (batchOptions?.returnExceptions) return e; - throw e; - } - })); - return Promise.all(batchCalls); - } - /** - * Default streaming implementation. - * Subclasses should override this method if they support streaming output. - * @param input - * @param options - */ - async *_streamIterator(input, options) { - yield this.invoke(input, options); - } - /** - * Stream output in chunks. - * @param input - * @param options - * @returns A readable stream that is also an iterable. - */ - async stream(input, options) { - const config = ensureConfig(options); - const wrappedGenerator = new AsyncGeneratorWithSetup({ - generator: this._streamIterator(input, config), - config - }); - await wrappedGenerator.setup; - return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); - } - _separateRunnableConfigFromCallOptions(options) { - let runnableConfig; - if (options === void 0) runnableConfig = ensureConfig(options); - else runnableConfig = ensureConfig({ - callbacks: options.callbacks, - tags: options.tags, - metadata: options.metadata, - runName: options.runName, - configurable: options.configurable, - recursionLimit: options.recursionLimit, - maxConcurrency: options.maxConcurrency, - runId: options.runId, - timeout: options.timeout, - signal: options.signal - }); - const callOptions = { ...options }; - delete callOptions.callbacks; - delete callOptions.tags; - delete callOptions.metadata; - delete callOptions.runName; - delete callOptions.configurable; - delete callOptions.recursionLimit; - delete callOptions.maxConcurrency; - delete callOptions.runId; - delete callOptions.timeout; - delete callOptions.signal; - return [runnableConfig, callOptions]; +function isInteropZodSchema(input) { + if (!input) return false; + if (typeof input !== "object") return false; + if (Array.isArray(input)) return false; + if (isZodSchemaV4(input) || isZodSchemaV3(input)) return true; + return false; +} +function isZodLiteralV3(obj) { + if (typeof obj === "object" && obj !== null && "_def" in obj && typeof obj._def === "object" && obj._def !== null && "typeName" in obj._def && obj._def.typeName === "ZodLiteral") return true; + return false; +} +function isZodLiteralV4(obj) { + if (!isZodSchemaV4(obj)) return false; + if (typeof obj === "object" && obj !== null && "_zod" in obj && typeof obj._zod === "object" && obj._zod !== null && "def" in obj._zod && typeof obj._zod.def === "object" && obj._zod.def !== null && "type" in obj._zod.def && obj._zod.def.type === "literal") return true; + return false; +} +/** +* Determines if the provided value is an InteropZodLiteral (Zod v3 or v4 literal schema). +* +* @param obj The value to check. +* @returns {boolean} True if the value is a Zod v3 or v4 literal schema, false otherwise. +*/ +function isInteropZodLiteral(obj) { + if (isZodLiteralV3(obj)) return true; + if (isZodLiteralV4(obj)) return true; + return false; +} +/** +* Asynchronously parses the input using the provided Zod schema (v3 or v4) and returns a safe parse result. +* This function handles both Zod v3 and v4 schemas, returning a result object indicating success or failure. +* +* @template T - The expected output type of the schema. +* @param {InteropZodType} schema - The Zod schema (v3 or v4) to use for parsing. +* @param {unknown} input - The input value to parse. +* @returns {Promise>} A promise that resolves to a safe parse result object. +* @throws {Error} If the schema is not a recognized Zod v3 or v4 schema. +*/ +async function interopSafeParseAsync(schema, input) { + if (isZodSchemaV4(schema)) try { + const data = await parseAsync(schema, input); + return { + success: true, + data + }; + } catch (error) { + return { + success: false, + error + }; } - async _callWithConfig(func, input, options) { - const config = ensureConfig(options); - const callbackManager_ = await getCallbackManagerForConfig(config); - const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), config.runId, config?.runType, void 0, void 0, config?.runName ?? this.getName()); - delete config.runId; - let output; - try { - const promise = func.call(this, input, config, runManager); - output = await raceWithSignal(promise, options?.signal); - } catch (e) { - await runManager?.handleChainError(e); - throw e; - } - await runManager?.handleChainEnd(base_coerceToDict(output, "output")); - return output; + if (isZodSchemaV3(schema)) return await schema.safeParseAsync(input); + throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); +} +/** +* Asynchronously parses the input using the provided Zod schema (v3 or v4) and returns the parsed value. +* Throws an error if parsing fails or if the schema is not a recognized Zod v3 or v4 schema. +* +* @template T - The expected output type of the schema. +* @param {InteropZodType} schema - The Zod schema (v3 or v4) to use for parsing. +* @param {unknown} input - The input value to parse. +* @returns {Promise} A promise that resolves to the parsed value. +* @throws {Error} If parsing fails or the schema is not a recognized Zod v3 or v4 schema. +*/ +async function interopParseAsync(schema, input) { + if (isZodSchemaV4(schema)) return await parseAsync(schema, input); + if (isZodSchemaV3(schema)) return await schema.parseAsync(input); + throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); +} +/** +* Safely parses the input using the provided Zod schema (v3 or v4) and returns a result object +* indicating success or failure. This function is compatible with both Zod v3 and v4 schemas. +* +* @template T - The expected output type of the schema. +* @param {InteropZodType} schema - The Zod schema (v3 or v4) to use for parsing. +* @param {unknown} input - The input value to parse. +* @returns {InteropZodSafeParseResult} An object with either the parsed data (on success) +* or the error (on failure). +* @throws {Error} If the schema is not a recognized Zod v3 or v4 schema. +*/ +function interopSafeParse(schema, input) { + if (isZodSchemaV4(schema)) try { + const data = parse_parse(schema, input); + return { + success: true, + data + }; + } catch (error) { + return { + success: false, + error + }; } - /** - * Internal method that handles batching and configuration for a runnable - * It takes a function, input values, and optional configuration, and - * returns a promise that resolves to the output values. - * @param func The function to be executed for each input value. - * @param input The input values to be processed. - * @param config Optional configuration for the function execution. - * @returns A promise that resolves to the output values. - */ - async _batchWithConfig(func, inputs, options, batchOptions) { - const optionsList = this._getOptionsList(options ?? {}, inputs.length); - const callbackManagers = await Promise.all(optionsList.map(getCallbackManagerForConfig)); - const runManagers = await Promise.all(callbackManagers.map(async (callbackManager, i) => { - const handleStartRes = await callbackManager?.handleChainStart(this.toJSON(), base_coerceToDict(inputs[i], "input"), optionsList[i].runId, optionsList[i].runType, void 0, void 0, optionsList[i].runName ?? this.getName()); - delete optionsList[i].runId; - return handleStartRes; - })); - let outputs; - try { - const promise = func.call(this, inputs, optionsList, runManagers, batchOptions); - outputs = await raceWithSignal(promise, optionsList?.[0]?.signal); - } catch (e) { - await Promise.all(runManagers.map((runManager) => runManager?.handleChainError(e))); - throw e; + if (isZodSchemaV3(schema)) return schema.safeParse(input); + throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); +} +/** +* Parses the input using the provided Zod schema (v3 or v4) and returns the parsed value. +* Throws an error if parsing fails or if the schema is not a recognized Zod v3 or v4 schema. +* +* @template T - The expected output type of the schema. +* @param {InteropZodType} schema - The Zod schema (v3 or v4) to use for parsing. +* @param {unknown} input - The input value to parse. +* @returns {T} The parsed value. +* @throws {Error} If parsing fails or the schema is not a recognized Zod v3 or v4 schema. +*/ +function interopParse(schema, input) { + if (isZodSchemaV4(schema)) return parse_parse(schema, input); + if (isZodSchemaV3(schema)) return schema.parse(input); + throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); +} +/** +* Retrieves the description from a schema definition (v3, v4, or plain object), if available. +* +* @param {unknown} schema - The schema to extract the description from. +* @returns {string | undefined} The description of the schema, or undefined if not present. +*/ +function getSchemaDescription(schema) { + if (isZodSchemaV4(schema)) return globalRegistry.get(schema)?.description; + if (isZodSchemaV3(schema)) return schema.description; + if ("description" in schema && typeof schema.description === "string") return schema.description; + return void 0; +} +/** +* Determines if the provided Zod schema is "shapeless". +* A shapeless schema is one that does not define any object shape, +* such as ZodString, ZodNumber, ZodBoolean, ZodAny, etc. +* For ZodObject, it must have no shape keys to be considered shapeless. +* ZodRecord schemas are considered shapeless since they define dynamic +* key-value mappings without fixed keys. +* +* @param schema The Zod schema to check. +* @returns {boolean} True if the schema is shapeless, false otherwise. +*/ +function isShapelessZodSchema(schema) { + if (!isInteropZodSchema(schema)) return false; + if (isZodSchemaV3(schema)) { + const def = schema._def; + if (def.typeName === "ZodObject") { + const obj = schema; + return !obj.shape || Object.keys(obj.shape).length === 0; } - await Promise.all(runManagers.map((runManager) => runManager?.handleChainEnd(base_coerceToDict(outputs, "output")))); - return outputs; - } - /** @internal */ - _concatOutputChunks(first, second) { - return concat(first, second); + if (def.typeName === "ZodRecord") return true; } - /** - * Helper method to transform an Iterator of Input values into an Iterator of - * Output values, with callbacks. - * Use this to implement `stream()` or `transform()` in Runnable subclasses. - */ - async *_transformStreamWithConfig(inputGenerator, transformer, options) { - let finalInput; - let finalInputSupported = true; - let finalOutput; - let finalOutputSupported = true; - const config = ensureConfig(options); - const callbackManager_ = await getCallbackManagerForConfig(config); - const outerThis = this; - async function* wrapInputForTracing() { - for await (const chunk of inputGenerator) { - if (finalInputSupported) if (finalInput === void 0) finalInput = chunk; - else try { - finalInput = outerThis._concatOutputChunks(finalInput, chunk); - } catch { - finalInput = void 0; - finalInputSupported = false; - } - yield chunk; - } - } - let runManager; - try { - const pipe = await pipeGeneratorWithSetup(transformer.bind(this), wrapInputForTracing(), async () => callbackManager_?.handleChainStart(this.toJSON(), { input: "" }, config.runId, config.runType, void 0, void 0, config.runName ?? this.getName()), options?.signal, config); - delete config.runId; - runManager = pipe.setup; - const streamEventsHandler = runManager?.handlers.find(isStreamEventsHandler); - let iterator = pipe.output; - if (streamEventsHandler !== void 0 && runManager !== void 0) iterator = streamEventsHandler.tapOutputIterable(runManager.runId, iterator); - const streamLogHandler = runManager?.handlers.find(isLogStreamHandler); - if (streamLogHandler !== void 0 && runManager !== void 0) iterator = streamLogHandler.tapOutputIterable(runManager.runId, iterator); - for await (const chunk of iterator) { - yield chunk; - if (finalOutputSupported) if (finalOutput === void 0) finalOutput = chunk; - else try { - finalOutput = this._concatOutputChunks(finalOutput, chunk); - } catch { - finalOutput = void 0; - finalOutputSupported = false; - } - } - } catch (e) { - await runManager?.handleChainError(e, void 0, void 0, void 0, { inputs: base_coerceToDict(finalInput, "input") }); - throw e; + if (isZodSchemaV4(schema)) { + const def = schema._zod.def; + if (def.type === "object") { + const obj = schema; + return !obj.shape || Object.keys(obj.shape).length === 0; } - await runManager?.handleChainEnd(finalOutput ?? {}, void 0, void 0, void 0, { inputs: base_coerceToDict(finalInput, "input") }); - } - getGraph(_) { - const graph = new Graph(); - const inputNode = graph.addNode({ - name: `${this.getName()}Input`, - schema: anyType() - }); - const runnableNode = graph.addNode(this); - const outputNode = graph.addNode({ - name: `${this.getName()}Output`, - schema: anyType() - }); - graph.addEdge(inputNode, runnableNode); - graph.addEdge(runnableNode, outputNode); - return graph; - } - /** - * Create a new runnable sequence that runs each individual runnable in series, - * piping the output of one runnable into another runnable or runnable-like. - * @param coerceable A runnable, function, or object whose values are functions or runnables. - * @returns A new runnable sequence. - */ - pipe(coerceable) { - return new RunnableSequence({ - first: this, - last: _coerceToRunnable(coerceable) - }); - } - /** - * Pick keys from the dict output of this runnable. Returns a new runnable. - */ - pick(keys) { - return this.pipe(new RunnablePick(keys)); - } - /** - * Assigns new fields to the dict output of this runnable. Returns a new runnable. - */ - assign(mapping) { - return this.pipe(new RunnableAssign(new RunnableMap({ steps: mapping }))); - } - /** - * Default implementation of transform, which buffers input and then calls stream. - * Subclasses should override this method if they can start producing output while - * input is still being generated. - * @param generator - * @param options - */ - async *transform(generator, options) { - let finalChunk; - for await (const chunk of generator) if (finalChunk === void 0) finalChunk = chunk; - else finalChunk = this._concatOutputChunks(finalChunk, chunk); - yield* this._streamIterator(finalChunk, ensureConfig(options)); - } - /** - * Stream all output from a runnable, as reported to the callback system. - * This includes all inner runs of LLMs, Retrievers, Tools, etc. - * Output is streamed as Log objects, which include a list of - * jsonpatch ops that describe how the state of the run has changed in each - * step, and the final state of the run. - * The jsonpatch ops can be applied in order to construct state. - * @param input - * @param options - * @param streamOptions - */ - async *streamLog(input, options, streamOptions) { - const logStreamCallbackHandler = new LogStreamCallbackHandler({ - ...streamOptions, - autoClose: false, - _schemaFormat: "original" - }); - const config = ensureConfig(options); - yield* this._streamLog(input, logStreamCallbackHandler, config); + if (def.type === "record") return true; } - async *_streamLog(input, logStreamCallbackHandler, config) { - const { callbacks } = config; - if (callbacks === void 0) config.callbacks = [logStreamCallbackHandler]; - else if (Array.isArray(callbacks)) config.callbacks = callbacks.concat([logStreamCallbackHandler]); - else { - const copiedCallbacks = callbacks.copy(); - copiedCallbacks.addHandler(logStreamCallbackHandler, true); - config.callbacks = copiedCallbacks; - } - const runnableStreamPromise = this.stream(input, config); - async function consumeRunnableStream() { - try { - const runnableStream = await runnableStreamPromise; - for await (const chunk of runnableStream) { - const patch = new RunLogPatch({ ops: [{ - op: "add", - path: "/streamed_output/-", - value: chunk - }] }); - await logStreamCallbackHandler.writer.write(patch); - } - } finally { - await logStreamCallbackHandler.writer.close(); - } - } - const runnableStreamConsumePromise = consumeRunnableStream(); - try { - for await (const log of logStreamCallbackHandler) yield log; - } finally { - await runnableStreamConsumePromise; - } + if (typeof schema === "object" && schema !== null && !("shape" in schema)) return true; + return false; +} +/** +* Determines if the provided Zod schema should be treated as a simple string schema +* that maps to DynamicTool. This aligns with the type-level constraint of +* InteropZodType which only matches basic string schemas. +* If the provided schema is just z.string(), we can make the determination that +* the tool is just a generic string tool that doesn't require any input validation. +* +* This function only returns true for basic ZodString schemas, including: +* - Basic string schemas (z.string()) +* - String schemas with validations (z.string().min(1), z.string().email(), etc.) +* +* This function returns false for everything else, including: +* - String schemas with defaults (z.string().default("value")) +* - Branded string schemas (z.string().brand<"UserId">()) +* - String schemas with catch operations (z.string().catch("default")) +* - Optional/nullable string schemas (z.string().optional()) +* - Transformed schemas (z.string().transform() or z.object().transform()) +* - Object or record schemas, even if they're empty +* - Any other schema type +* +* @param schema The Zod schema to check. +* @returns {boolean} True if the schema is a basic ZodString, false otherwise. +*/ +function isSimpleStringZodSchema(schema) { + if (!isInteropZodSchema(schema)) return false; + if (isZodSchemaV3(schema)) { + const def = schema._def; + return def.typeName === "ZodString"; } - streamEvents(input, options, streamOptions) { - let stream; - if (options.version === "v1") stream = this._streamEventsV1(input, options, streamOptions); - else if (options.version === "v2") stream = this._streamEventsV2(input, options, streamOptions); - else throw new Error(`Only versions "v1" and "v2" of the schema are currently supported.`); - if (options.encoding === "text/event-stream") return convertToHttpEventStream(stream); - else return IterableReadableStream.fromAsyncGenerator(stream); + if (isZodSchemaV4(schema)) { + const def = schema._zod.def; + return def.type === "string"; } - async *_streamEventsV2(input, options, streamOptions) { - const eventStreamer = new EventStreamCallbackHandler({ - ...streamOptions, - autoClose: false - }); - const config = ensureConfig(options); - const runId = config.runId ?? v4(); - config.runId = runId; - const callbacks = config.callbacks; - if (callbacks === void 0) config.callbacks = [eventStreamer]; - else if (Array.isArray(callbacks)) config.callbacks = callbacks.concat(eventStreamer); - else { - const copiedCallbacks = callbacks.copy(); - copiedCallbacks.addHandler(eventStreamer, true); - config.callbacks = copiedCallbacks; - } - const abortController = new AbortController(); - const outerThis = this; - async function consumeRunnableStream() { - let signal; - let listener = null; - try { - if (options?.signal) if ("any" in AbortSignal) signal = AbortSignal.any([abortController.signal, options.signal]); - else { - signal = options.signal; - listener = () => { - abortController.abort(); - }; - options.signal.addEventListener("abort", listener, { once: true }); - } - else signal = abortController.signal; - const runnableStream = await outerThis.stream(input, { - ...config, - signal + return false; +} +function isZodObjectV3(obj) { + if (typeof obj === "object" && obj !== null && "_def" in obj && typeof obj._def === "object" && obj._def !== null && "typeName" in obj._def && obj._def.typeName === "ZodObject") return true; + return false; +} +function isZodObjectV4(obj) { + if (!isZodSchemaV4(obj)) return false; + if (typeof obj === "object" && obj !== null && "_zod" in obj && typeof obj._zod === "object" && obj._zod !== null && "def" in obj._zod && typeof obj._zod.def === "object" && obj._zod.def !== null && "type" in obj._zod.def && obj._zod.def.type === "object") return true; + return false; +} +function isZodArrayV4(obj) { + if (!isZodSchemaV4(obj)) return false; + if (typeof obj === "object" && obj !== null && "_zod" in obj && typeof obj._zod === "object" && obj._zod !== null && "def" in obj._zod && typeof obj._zod.def === "object" && obj._zod.def !== null && "type" in obj._zod.def && obj._zod.def.type === "array") return true; + return false; +} +function isZodOptionalV4(obj) { + if (!isZodSchemaV4(obj)) return false; + if (typeof obj === "object" && obj !== null && "_zod" in obj && typeof obj._zod === "object" && obj._zod !== null && "def" in obj._zod && typeof obj._zod.def === "object" && obj._zod.def !== null && "type" in obj._zod.def && obj._zod.def.type === "optional") return true; + return false; +} +function isZodNullableV4(obj) { + if (!isZodSchemaV4(obj)) return false; + if (typeof obj === "object" && obj !== null && "_zod" in obj && typeof obj._zod === "object" && obj._zod !== null && "def" in obj._zod && typeof obj._zod.def === "object" && obj._zod.def !== null && "type" in obj._zod.def && obj._zod.def.type === "nullable") return true; + return false; +} +/** +* Determines if the provided value is an InteropZodObject (Zod v3 or v4 object schema). +* +* @param obj The value to check. +* @returns {boolean} True if the value is a Zod v3 or v4 object schema, false otherwise. +*/ +function isInteropZodObject(obj) { + if (isZodObjectV3(obj)) return true; + if (isZodObjectV4(obj)) return true; + return false; +} +/** +* Retrieves the shape (fields) of a Zod object schema, supporting both Zod v3 and v4. +* +* @template T - The type of the Zod object schema. +* @param {T} schema - The Zod object schema instance (either v3 or v4). +* @returns {InteropZodObjectShape} The shape of the object schema. +* @throws {Error} If the schema is not a Zod v3 or v4 object. +*/ +function getInteropZodObjectShape(schema) { + if (isZodSchemaV3(schema)) return schema.shape; + if (isZodSchemaV4(schema)) return schema._zod.def.shape; + throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); +} +/** +* Extends a Zod object schema with additional fields, supporting both Zod v3 and v4. +* +* @template T - The type of the Zod object schema. +* @param {T} schema - The Zod object schema instance (either v3 or v4). +* @param {InteropZodObjectShape} extension - The fields to add to the schema. +* @returns {InteropZodObject} The extended Zod object schema. +* @throws {Error} If the schema is not a Zod v3 or v4 object. +*/ +function extendInteropZodObject(schema, extension) { + if (isZodSchemaV3(schema)) return schema.extend(extension); + if (isZodSchemaV4(schema)) return extend(schema, extension); + throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); +} +/** +* Returns a partial version of a Zod object schema, making all fields optional. +* Supports both Zod v3 and v4. +* +* @template T - The type of the Zod object schema. +* @param {T} schema - The Zod object schema instance (either v3 or v4). +* @returns {InteropZodObject} The partial Zod object schema. +* @throws {Error} If the schema is not a Zod v3 or v4 object. +*/ +function interopZodObjectPartial(schema) { + if (isZodSchemaV3(schema)) return schema.partial(); + if (isZodSchemaV4(schema)) return partial($ZodOptional, schema, void 0); + throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); +} +/** +* Returns a strict version of a Zod object schema, disallowing unknown keys. +* Supports both Zod v3 and v4 object schemas. If `recursive` is true, applies strictness +* recursively to all nested object schemas and arrays of object schemas. +* +* @template T - The type of the Zod object schema. +* @param {T} schema - The Zod object schema instance (either v3 or v4). +* @param {boolean} [recursive=false] - Whether to apply strictness recursively to nested objects/arrays. +* @returns {InteropZodObject} The strict Zod object schema. +* @throws {Error} If the schema is not a Zod v3 or v4 object. +*/ +function interopZodObjectStrict(schema, recursive = false) { + if (isZodSchemaV3(schema)) return schema.strict(); + if (isZodObjectV4(schema)) { + const outputShape = schema._zod.def.shape; + if (recursive) for (const [key, keySchema] of Object.entries(schema._zod.def.shape)) { + if (isZodObjectV4(keySchema)) { + const outputSchema = interopZodObjectStrict(keySchema, recursive); + outputShape[key] = outputSchema; + } else if (isZodArrayV4(keySchema)) { + let elementSchema = keySchema._zod.def.element; + if (isZodObjectV4(elementSchema)) elementSchema = interopZodObjectStrict(elementSchema, recursive); + outputShape[key] = clone(keySchema, { + ...keySchema._zod.def, + element: elementSchema }); - const tappedStream = eventStreamer.tapOutputIterable(runId, runnableStream); - for await (const _ of tappedStream) if (abortController.signal.aborted) break; - } finally { - await eventStreamer.finish(); - if (signal && listener) signal.removeEventListener("abort", listener); - } - } - const runnableStreamConsumePromise = consumeRunnableStream(); - let firstEventSent = false; - let firstEventRunId; - try { - for await (const event of eventStreamer) { - if (!firstEventSent) { - event.data.input = input; - firstEventSent = true; - firstEventRunId = event.run_id; - yield event; - continue; - } - if (event.run_id === firstEventRunId && event.event.endsWith("_end")) { - if (event.data?.input) delete event.data.input; - } - yield event; - } - } finally { - abortController.abort(); - await runnableStreamConsumePromise; + } else outputShape[key] = keySchema; + const meta$1 = globalRegistry.get(keySchema); + if (meta$1) globalRegistry.add(outputShape[key], meta$1); } + const modifiedSchema = clone(schema, { + ...schema._zod.def, + shape: outputShape, + catchall: _never($ZodNever) + }); + const meta = globalRegistry.get(schema); + if (meta) globalRegistry.add(modifiedSchema, meta); + return modifiedSchema; } - async *_streamEventsV1(input, options, streamOptions) { - let runLog; - let hasEncounteredStartEvent = false; - const config = ensureConfig(options); - const rootTags = config.tags ?? []; - const rootMetadata = config.metadata ?? {}; - const rootName = config.runName ?? this.getName(); - const logStreamCallbackHandler = new LogStreamCallbackHandler({ - ...streamOptions, - autoClose: false, - _schemaFormat: "streaming_events" + throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); +} +/** +* Returns a passthrough version of a Zod object schema, allowing unknown keys. +* Supports both Zod v3 and v4 object schemas. If `recursive` is true, applies passthrough +* recursively to all nested object schemas and arrays of object schemas. +* +* @template T - The type of the Zod object schema. +* @param {T} schema - The Zod object schema instance (either v3 or v4). +* @param {boolean} [recursive=false] - Whether to apply passthrough recursively to nested objects/arrays. +* @returns {InteropZodObject} The passthrough Zod object schema. +* @throws {Error} If the schema is not a Zod v3 or v4 object. +*/ +function interopZodObjectPassthrough(schema, recursive = false) { + if (isZodObjectV3(schema)) return schema.passthrough(); + if (isZodObjectV4(schema)) { + const outputShape = schema._zod.def.shape; + if (recursive) for (const [key, keySchema] of Object.entries(schema._zod.def.shape)) { + if (isZodObjectV4(keySchema)) { + const outputSchema = interopZodObjectPassthrough(keySchema, recursive); + outputShape[key] = outputSchema; + } else if (isZodArrayV4(keySchema)) { + let elementSchema = keySchema._zod.def.element; + if (isZodObjectV4(elementSchema)) elementSchema = interopZodObjectPassthrough(elementSchema, recursive); + outputShape[key] = clone(keySchema, { + ...keySchema._zod.def, + element: elementSchema + }); + } else outputShape[key] = keySchema; + const meta$1 = globalRegistry.get(keySchema); + if (meta$1) globalRegistry.add(outputShape[key], meta$1); + } + const modifiedSchema = clone(schema, { + ...schema._zod.def, + shape: outputShape, + catchall: _unknown($ZodUnknown) }); - const rootEventFilter = new _RootEventFilter({ ...streamOptions }); - const logStream = this._streamLog(input, logStreamCallbackHandler, config); - for await (const log of logStream) { - if (!runLog) runLog = RunLog.fromRunLogPatch(log); - else runLog = runLog.concat(log); - if (runLog.state === void 0) throw new Error(`Internal error: "streamEvents" state is missing. Please open a bug report.`); - if (!hasEncounteredStartEvent) { - hasEncounteredStartEvent = true; - const state$2 = { ...runLog.state }; - const event = { - run_id: state$2.id, - event: `on_${state$2.type}_start`, - name: rootName, - tags: rootTags, - metadata: rootMetadata, - data: { input } - }; - if (rootEventFilter.includeEvent(event, state$2.type)) yield event; - } - const paths = log.ops.filter((op) => op.path.startsWith("/logs/")).map((op) => op.path.split("/")[2]); - const dedupedPaths = [...new Set(paths)]; - for (const path of dedupedPaths) { - let eventType; - let data = {}; - const logEntry = runLog.state.logs[path]; - if (logEntry.end_time === void 0) if (logEntry.streamed_output.length > 0) eventType = "stream"; - else eventType = "start"; - else eventType = "end"; - if (eventType === "start") { - if (logEntry.inputs !== void 0) data.input = logEntry.inputs; - } else if (eventType === "end") { - if (logEntry.inputs !== void 0) data.input = logEntry.inputs; - data.output = logEntry.final_output; - } else if (eventType === "stream") { - const chunkCount = logEntry.streamed_output.length; - if (chunkCount !== 1) throw new Error(`Expected exactly one chunk of streamed output, got ${chunkCount} instead. Encountered in: "${logEntry.name}"`); - data = { chunk: logEntry.streamed_output[0] }; - logEntry.streamed_output = []; - } - yield { - event: `on_${logEntry.type}_${eventType}`, - name: logEntry.name, - run_id: logEntry.id, - tags: logEntry.tags, - metadata: logEntry.metadata, - data - }; - } - const { state: state$1 } = runLog; - if (state$1.streamed_output.length > 0) { - const chunkCount = state$1.streamed_output.length; - if (chunkCount !== 1) throw new Error(`Expected exactly one chunk of streamed output, got ${chunkCount} instead. Encountered in: "${state$1.name}"`); - const data = { chunk: state$1.streamed_output[0] }; - state$1.streamed_output = []; - const event = { - event: `on_${state$1.type}_stream`, - run_id: state$1.id, - tags: rootTags, - metadata: rootMetadata, - name: rootName, - data - }; - if (rootEventFilter.includeEvent(event, state$1.type)) yield event; + const meta = globalRegistry.get(schema); + if (meta) globalRegistry.add(modifiedSchema, meta); + return modifiedSchema; + } + throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); +} +/** +* Returns a getter function for the default value of a Zod schema, if one is defined. +* Supports both Zod v3 and v4 schemas. If the schema has a default value, +* the returned function will return that value when called. If no default is defined, +* returns undefined. +* +* @template T - The type of the Zod schema. +* @param {T} schema - The Zod schema instance (either v3 or v4). +* @returns {(() => InferInteropZodOutput) | undefined} A function that returns the default value, or undefined if no default is set. +*/ +function getInteropZodDefaultGetter(schema) { + if (isZodSchemaV3(schema)) try { + const defaultValue = schema.parse(void 0); + return () => defaultValue; + } catch { + return void 0; + } + if (isZodSchemaV4(schema)) try { + const defaultValue = parse_parse(schema, void 0); + return () => defaultValue; + } catch { + return void 0; + } + return void 0; +} +function isZodTransformV3(schema) { + return isZodSchemaV3(schema) && "typeName" in schema._def && schema._def.typeName === "ZodEffects"; +} +function isZodTransformV4(schema) { + return isZodSchemaV4(schema) && schema._zod.def.type === "pipe"; +} +function interopZodTransformInputSchemaImpl(schema, recursive, cache) { + const cached = cache.get(schema); + if (cached !== void 0) return cached; + if (isZodSchemaV3(schema)) { + if (isZodTransformV3(schema)) return interopZodTransformInputSchemaImpl(schema._def.schema, recursive, cache); + return schema; + } + if (isZodSchemaV4(schema)) { + let outputSchema = schema; + if (isZodTransformV4(schema)) outputSchema = interopZodTransformInputSchemaImpl(schema._zod.def.in, recursive, cache); + if (recursive) { + if (isZodObjectV4(outputSchema)) { + const outputShape = {}; + for (const [key, keySchema] of Object.entries(outputSchema._zod.def.shape)) outputShape[key] = interopZodTransformInputSchemaImpl(keySchema, recursive, cache); + outputSchema = clone(outputSchema, { + ...outputSchema._zod.def, + shape: outputShape + }); + } else if (isZodArrayV4(outputSchema)) { + const elementSchema = interopZodTransformInputSchemaImpl(outputSchema._zod.def.element, recursive, cache); + outputSchema = clone(outputSchema, { + ...outputSchema._zod.def, + element: elementSchema + }); + } else if (isZodOptionalV4(outputSchema)) { + const innerSchema = interopZodTransformInputSchemaImpl(outputSchema._zod.def.innerType, recursive, cache); + outputSchema = clone(outputSchema, { + ...outputSchema._zod.def, + innerType: innerSchema + }); + } else if (isZodNullableV4(outputSchema)) { + const innerSchema = interopZodTransformInputSchemaImpl(outputSchema._zod.def.innerType, recursive, cache); + outputSchema = clone(outputSchema, { + ...outputSchema._zod.def, + innerType: innerSchema + }); } } - const state = runLog?.state; - if (state !== void 0) { - const event = { - event: `on_${state.type}_end`, - name: rootName, - run_id: state.id, - tags: rootTags, - metadata: rootMetadata, - data: { output: state.final_output } - }; - if (rootEventFilter.includeEvent(event, state.type)) yield event; - } + const meta = globalRegistry.get(schema); + if (meta) globalRegistry.add(outputSchema, meta); + cache.set(schema, outputSchema); + return outputSchema; } - static isRunnable(thing) { - return isRunnableInterface(thing); + throw new Error("Schema must be an instance of z3.ZodType or z4.$ZodType"); +} +/** +* Returns the input type of a Zod transform schema, for both v3 and v4. +* If the schema is not a transform, returns undefined. If `recursive` is true, +* recursively processes nested object schemas and arrays of object schemas. +* +* @param schema - The Zod schema instance (v3 or v4) +* @param {boolean} [recursive=false] - Whether to recursively process nested objects/arrays. +* @returns The input Zod schema of the transform, or undefined if not a transform +*/ +function interopZodTransformInputSchema(schema, recursive = false) { + const cache = /* @__PURE__ */ new WeakMap(); + return interopZodTransformInputSchemaImpl(schema, recursive, cache); +} +/** +* Creates a modified version of a Zod object schema where fields matching a predicate are made optional. +* Supports both Zod v3 and v4 schemas and preserves the original schema version. +* +* @template T - The type of the Zod object schema. +* @param {T} schema - The Zod object schema instance (either v3 or v4). +* @param {(key: string, value: InteropZodType) => boolean} predicate - Function to determine which fields should be optional. +* @returns {InteropZodObject} The modified Zod object schema. +* @throws {Error} If the schema is not a Zod v3 or v4 object. +*/ +function interopZodObjectMakeFieldsOptional(schema, predicate) { + if (isZodSchemaV3(schema)) { + const shape = getInteropZodObjectShape(schema); + const modifiedShape = {}; + for (const [key, value] of Object.entries(shape)) if (predicate(key, value)) modifiedShape[key] = value.optional(); + else modifiedShape[key] = value; + return schema.extend(modifiedShape); } - /** - * Bind lifecycle listeners to a Runnable, returning a new Runnable. - * The Run object contains information about the run, including its id, - * type, input, output, error, startTime, endTime, and any tags or metadata - * added to the run. - * - * @param {Object} params - The object containing the callback functions. - * @param {(run: Run) => void} params.onStart - Called before the runnable starts running, with the Run object. - * @param {(run: Run) => void} params.onEnd - Called after the runnable finishes running, with the Run object. - * @param {(run: Run) => void} params.onError - Called if the runnable throws an error, with the Run object. - */ - withListeners({ onStart, onEnd, onError }) { - return new RunnableBinding({ - bound: this, - config: {}, - configFactories: [(config) => ({ callbacks: [new RootListenersTracer({ - config, - onStart, - onEnd, - onError - })] })] + if (isZodSchemaV4(schema)) { + const shape = getInteropZodObjectShape(schema); + const outputShape = { ...schema._zod.def.shape }; + for (const [key, value] of Object.entries(shape)) if (predicate(key, value)) outputShape[key] = new $ZodOptional({ + type: "optional", + innerType: value }); + const modifiedSchema = clone(schema, { + ...schema._zod.def, + shape: outputShape + }); + const meta = globalRegistry.get(schema); + if (meta) globalRegistry.add(modifiedSchema, meta); + return modifiedSchema; } - /** - * Convert a runnable to a tool. Return a new instance of `RunnableToolLike` - * which contains the runnable, name, description and schema. - * - * @template {T extends RunInput = RunInput} RunInput - The input type of the runnable. Should be the same as the `RunInput` type of the runnable. - * - * @param fields - * @param {string | undefined} [fields.name] The name of the tool. If not provided, it will default to the name of the runnable. - * @param {string | undefined} [fields.description] The description of the tool. Falls back to the description on the Zod schema if not provided, or undefined if neither are provided. - * @param {z.ZodType} [fields.schema] The Zod schema for the input of the tool. Infers the Zod type from the input type of the runnable. - * @returns {RunnableToolLike, RunOutput>} An instance of `RunnableToolLike` which is a runnable that can be used as a tool. - */ - asTool(fields) { - return convertRunnableToTool(this, fields); - } + throw new Error("Schema must be an instance of z3.ZodObject or z4.$ZodObject"); +} +function isInteropZodError(e) { + return e instanceof Error && (e.constructor.name === "ZodError" || e.constructor.name === "$ZodError"); +} + +//#endregion + +//# sourceMappingURL=zod.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/Options.js +//#region src/utils/zod-to-json-schema/Options.ts +const ignoreOverride = Symbol("Let zodToJsonSchema decide on which parser to use"); +const Options_defaultOptions = { + name: void 0, + $refStrategy: "root", + basePath: ["#"], + effectStrategy: "input", + pipeStrategy: "all", + dateStrategy: "format:date-time", + mapStrategy: "entries", + removeAdditionalStrategy: "passthrough", + allowedAdditionalProperties: true, + rejectedAdditionalProperties: false, + definitionPath: "definitions", + target: "jsonSchema7", + strictUnions: false, + definitions: {}, + errorMessages: false, + markdownDescription: false, + patternStrategy: "escape", + applyRegexFlags: false, + emailStrategy: "format:email", + base64Strategy: "contentEncoding:base64", + nameStrategy: "ref", + openAiAnyTypeName: "OpenAiAnyType" +}; +const getDefaultOptions = (options) => typeof options === "string" ? { + ...Options_defaultOptions, + name: options +} : { + ...Options_defaultOptions, + ...options +}; + +//#endregion + +//# sourceMappingURL=Options.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/Refs.js + + +//#region src/utils/zod-to-json-schema/Refs.ts +const getRefs = (options) => { + const _options = getDefaultOptions(options); + const currentPath = _options.name !== void 0 ? [ + ..._options.basePath, + _options.definitionPath, + _options.name + ] : _options.basePath; + return { + ..._options, + flags: { hasReferencedOpenAiAnyType: false }, + currentPath, + propertyPath: void 0, + seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [def._def, { + def: def._def, + path: [ + ..._options.basePath, + _options.definitionPath, + name + ], + jsonSchema: void 0 + }])) + }; +}; + +//#endregion + +//# sourceMappingURL=Refs.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/getRelativePath.js +//#region src/utils/zod-to-json-schema/getRelativePath.ts +const getRelativePath = (pathA, pathB) => { + let i = 0; + for (; i < pathA.length && i < pathB.length; i++) if (pathA[i] !== pathB[i]) break; + return [(pathA.length - i).toString(), ...pathB.slice(i)].join("/"); +}; + +//#endregion + +//# sourceMappingURL=getRelativePath.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/any.js + + +//#region src/utils/zod-to-json-schema/parsers/any.ts +function parseAnyDef(refs) { + if (refs.target !== "openAi") return {}; + const anyDefinitionPath = [ + ...refs.basePath, + refs.definitionPath, + refs.openAiAnyTypeName + ]; + refs.flags.hasReferencedOpenAiAnyType = true; + return { $ref: refs.$refStrategy === "relative" ? getRelativePath(anyDefinitionPath, refs.currentPath) : anyDefinitionPath.join("/") }; +} + +//#endregion + +//# sourceMappingURL=any.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/errorMessages.js +//#region src/utils/zod-to-json-schema/errorMessages.ts +function addErrorMessage(res, key, errorMessage, refs) { + if (!refs?.errorMessages) return; + if (errorMessage) res.errorMessage = { + ...res.errorMessage, + [key]: errorMessage + }; +} +function setResponseValueAndErrors(res, key, value, errorMessage, refs) { + res[key] = value; + addErrorMessage(res, key, errorMessage, refs); +} + +//#endregion + +//# sourceMappingURL=errorMessages.js.map +;// CONCATENATED MODULE: ./node_modules/zod/v3/helpers/util.js +var util_util; +(function (util) { + util.assertEqual = (_) => { }; + function assertIs(_arg) { } + util.assertIs = assertIs; + function assertNever(_x) { + throw new Error(); + } + util.assertNever = assertNever; + util.arrayToEnum = (items) => { + const obj = {}; + for (const item of items) { + obj[item] = item; + } + return obj; + }; + util.getValidEnumValues = (obj) => { + const validKeys = util.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number"); + const filtered = {}; + for (const k of validKeys) { + filtered[k] = obj[k]; + } + return util.objectValues(filtered); + }; + util.objectValues = (obj) => { + return util.objectKeys(obj).map(function (e) { + return obj[e]; + }); + }; + util.objectKeys = typeof Object.keys === "function" // eslint-disable-line ban/ban + ? (obj) => Object.keys(obj) // eslint-disable-line ban/ban + : (object) => { + const keys = []; + for (const key in object) { + if (Object.prototype.hasOwnProperty.call(object, key)) { + keys.push(key); + } + } + return keys; + }; + util.find = (arr, checker) => { + for (const item of arr) { + if (checker(item)) + return item; + } + return undefined; + }; + util.isInteger = typeof Number.isInteger === "function" + ? (val) => Number.isInteger(val) // eslint-disable-line ban/ban + : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val; + function joinValues(array, separator = " | ") { + return array.map((val) => (typeof val === "string" ? `'${val}'` : val)).join(separator); + } + util.joinValues = joinValues; + util.jsonStringifyReplacer = (_, value) => { + if (typeof value === "bigint") { + return value.toString(); + } + return value; + }; +})(util_util || (util_util = {})); +var objectUtil; +(function (objectUtil) { + objectUtil.mergeShapes = (first, second) => { + return { + ...first, + ...second, // second overwrites first + }; + }; +})(objectUtil || (objectUtil = {})); +const ZodParsedType = util_util.arrayToEnum([ + "string", + "nan", + "number", + "integer", + "float", + "boolean", + "date", + "bigint", + "symbol", + "function", + "undefined", + "null", + "array", + "object", + "unknown", + "promise", + "void", + "never", + "map", + "set", +]); +const util_getParsedType = (data) => { + const t = typeof data; + switch (t) { + case "undefined": + return ZodParsedType.undefined; + case "string": + return ZodParsedType.string; + case "number": + return Number.isNaN(data) ? ZodParsedType.nan : ZodParsedType.number; + case "boolean": + return ZodParsedType.boolean; + case "function": + return ZodParsedType.function; + case "bigint": + return ZodParsedType.bigint; + case "symbol": + return ZodParsedType.symbol; + case "object": + if (Array.isArray(data)) { + return ZodParsedType.array; + } + if (data === null) { + return ZodParsedType.null; + } + if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") { + return ZodParsedType.promise; + } + if (typeof Map !== "undefined" && data instanceof Map) { + return ZodParsedType.map; + } + if (typeof Set !== "undefined" && data instanceof Set) { + return ZodParsedType.set; + } + if (typeof Date !== "undefined" && data instanceof Date) { + return ZodParsedType.date; + } + return ZodParsedType.object; + default: + return ZodParsedType.unknown; + } +}; + +;// CONCATENATED MODULE: ./node_modules/zod/v3/ZodError.js + +const ZodIssueCode = util_util.arrayToEnum([ + "invalid_type", + "invalid_literal", + "custom", + "invalid_union", + "invalid_union_discriminator", + "invalid_enum_value", + "unrecognized_keys", + "invalid_arguments", + "invalid_return_type", + "invalid_date", + "invalid_string", + "too_small", + "too_big", + "invalid_intersection_types", + "not_multiple_of", + "not_finite", +]); +const quotelessJson = (obj) => { + const json = JSON.stringify(obj, null, 2); + return json.replace(/"([^"]+)":/g, "$1:"); +}; +class ZodError extends Error { + get errors() { + return this.issues; + } + constructor(issues) { + super(); + this.issues = []; + this.addIssue = (sub) => { + this.issues = [...this.issues, sub]; + }; + this.addIssues = (subs = []) => { + this.issues = [...this.issues, ...subs]; + }; + const actualProto = new.target.prototype; + if (Object.setPrototypeOf) { + // eslint-disable-next-line ban/ban + Object.setPrototypeOf(this, actualProto); + } + else { + this.__proto__ = actualProto; + } + this.name = "ZodError"; + this.issues = issues; + } + format(_mapper) { + const mapper = _mapper || + function (issue) { + return issue.message; + }; + const fieldErrors = { _errors: [] }; + const processError = (error) => { + for (const issue of error.issues) { + if (issue.code === "invalid_union") { + issue.unionErrors.map(processError); + } + else if (issue.code === "invalid_return_type") { + processError(issue.returnTypeError); + } + else if (issue.code === "invalid_arguments") { + processError(issue.argumentsError); + } + else if (issue.path.length === 0) { + fieldErrors._errors.push(mapper(issue)); + } + else { + let curr = fieldErrors; + let i = 0; + while (i < issue.path.length) { + const el = issue.path[i]; + const terminal = i === issue.path.length - 1; + if (!terminal) { + curr[el] = curr[el] || { _errors: [] }; + // if (typeof el === "string") { + // curr[el] = curr[el] || { _errors: [] }; + // } else if (typeof el === "number") { + // const errorArray: any = []; + // errorArray._errors = []; + // curr[el] = curr[el] || errorArray; + // } + } + else { + curr[el] = curr[el] || { _errors: [] }; + curr[el]._errors.push(mapper(issue)); + } + curr = curr[el]; + i++; + } + } + } + }; + processError(this); + return fieldErrors; + } + static assert(value) { + if (!(value instanceof ZodError)) { + throw new Error(`Not a ZodError: ${value}`); + } + } + toString() { + return this.message; + } + get message() { + return JSON.stringify(this.issues, util_util.jsonStringifyReplacer, 2); + } + get isEmpty() { + return this.issues.length === 0; + } + flatten(mapper = (issue) => issue.message) { + const fieldErrors = {}; + const formErrors = []; + for (const sub of this.issues) { + if (sub.path.length > 0) { + const firstEl = sub.path[0]; + fieldErrors[firstEl] = fieldErrors[firstEl] || []; + fieldErrors[firstEl].push(mapper(sub)); + } + else { + formErrors.push(mapper(sub)); + } + } + return { formErrors, fieldErrors }; + } + get formErrors() { + return this.flatten(); + } +} +ZodError.create = (issues) => { + const error = new ZodError(issues); + return error; +}; + +;// CONCATENATED MODULE: ./node_modules/zod/v3/locales/en.js + + +const errorMap = (issue, _ctx) => { + let message; + switch (issue.code) { + case ZodIssueCode.invalid_type: + if (issue.received === ZodParsedType.undefined) { + message = "Required"; + } + else { + message = `Expected ${issue.expected}, received ${issue.received}`; + } + break; + case ZodIssueCode.invalid_literal: + message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util_util.jsonStringifyReplacer)}`; + break; + case ZodIssueCode.unrecognized_keys: + message = `Unrecognized key(s) in object: ${util_util.joinValues(issue.keys, ", ")}`; + break; + case ZodIssueCode.invalid_union: + message = `Invalid input`; + break; + case ZodIssueCode.invalid_union_discriminator: + message = `Invalid discriminator value. Expected ${util_util.joinValues(issue.options)}`; + break; + case ZodIssueCode.invalid_enum_value: + message = `Invalid enum value. Expected ${util_util.joinValues(issue.options)}, received '${issue.received}'`; + break; + case ZodIssueCode.invalid_arguments: + message = `Invalid function arguments`; + break; + case ZodIssueCode.invalid_return_type: + message = `Invalid function return type`; + break; + case ZodIssueCode.invalid_date: + message = `Invalid date`; + break; + case ZodIssueCode.invalid_string: + if (typeof issue.validation === "object") { + if ("includes" in issue.validation) { + message = `Invalid input: must include "${issue.validation.includes}"`; + if (typeof issue.validation.position === "number") { + message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`; + } + } + else if ("startsWith" in issue.validation) { + message = `Invalid input: must start with "${issue.validation.startsWith}"`; + } + else if ("endsWith" in issue.validation) { + message = `Invalid input: must end with "${issue.validation.endsWith}"`; + } + else { + util_util.assertNever(issue.validation); + } + } + else if (issue.validation !== "regex") { + message = `Invalid ${issue.validation}`; + } + else { + message = "Invalid"; + } + break; + case ZodIssueCode.too_small: + if (issue.type === "array") + message = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`; + else if (issue.type === "string") + message = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`; + else if (issue.type === "number") + message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`; + else if (issue.type === "bigint") + message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`; + else if (issue.type === "date") + message = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`; + else + message = "Invalid input"; + break; + case ZodIssueCode.too_big: + if (issue.type === "array") + message = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`; + else if (issue.type === "string") + message = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`; + else if (issue.type === "number") + message = `Number must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`; + else if (issue.type === "bigint") + message = `BigInt must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`; + else if (issue.type === "date") + message = `Date must be ${issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`} ${new Date(Number(issue.maximum))}`; + else + message = "Invalid input"; + break; + case ZodIssueCode.custom: + message = `Invalid input`; + break; + case ZodIssueCode.invalid_intersection_types: + message = `Intersection results could not be merged`; + break; + case ZodIssueCode.not_multiple_of: + message = `Number must be a multiple of ${issue.multipleOf}`; + break; + case ZodIssueCode.not_finite: + message = "Number must be finite"; + break; + default: + message = _ctx.defaultError; + util_util.assertNever(issue); + } + return { message }; +}; +/* harmony default export */ const en = (errorMap); + +;// CONCATENATED MODULE: ./node_modules/zod/v3/errors.js + +let overrideErrorMap = en; + +function setErrorMap(map) { + overrideErrorMap = map; +} +function getErrorMap() { + return overrideErrorMap; +} + +;// CONCATENATED MODULE: ./node_modules/zod/v3/helpers/errorUtil.js +var errorUtil; +(function (errorUtil) { + errorUtil.errToObj = (message) => typeof message === "string" ? { message } : message || {}; + // biome-ignore lint: + errorUtil.toString = (message) => typeof message === "string" ? message : message?.message; +})(errorUtil || (errorUtil = {})); + +;// CONCATENATED MODULE: ./node_modules/zod/v3/helpers/parseUtil.js + + +const makeIssue = (params) => { + const { data, path, errorMaps, issueData } = params; + const fullPath = [...path, ...(issueData.path || [])]; + const fullIssue = { + ...issueData, + path: fullPath, + }; + if (issueData.message !== undefined) { + return { + ...issueData, + path: fullPath, + message: issueData.message, + }; + } + let errorMessage = ""; + const maps = errorMaps + .filter((m) => !!m) + .slice() + .reverse(); + for (const map of maps) { + errorMessage = map(fullIssue, { data, defaultError: errorMessage }).message; + } + return { + ...issueData, + path: fullPath, + message: errorMessage, + }; +}; +const EMPTY_PATH = (/* unused pure expression or super */ null && ([])); +function addIssueToContext(ctx, issueData) { + const overrideMap = getErrorMap(); + const issue = makeIssue({ + issueData: issueData, + data: ctx.data, + path: ctx.path, + errorMaps: [ + ctx.common.contextualErrorMap, // contextual error map is first priority + ctx.schemaErrorMap, // then schema-bound map if available + overrideMap, // then global override map + overrideMap === en ? undefined : en, // then global default map + ].filter((x) => !!x), + }); + ctx.common.issues.push(issue); +} +class ParseStatus { + constructor() { + this.value = "valid"; + } + dirty() { + if (this.value === "valid") + this.value = "dirty"; + } + abort() { + if (this.value !== "aborted") + this.value = "aborted"; + } + static mergeArray(status, results) { + const arrayValue = []; + for (const s of results) { + if (s.status === "aborted") + return parseUtil_INVALID; + if (s.status === "dirty") + status.dirty(); + arrayValue.push(s.value); + } + return { status: status.value, value: arrayValue }; + } + static async mergeObjectAsync(status, pairs) { + const syncPairs = []; + for (const pair of pairs) { + const key = await pair.key; + const value = await pair.value; + syncPairs.push({ + key, + value, + }); + } + return ParseStatus.mergeObjectSync(status, syncPairs); + } + static mergeObjectSync(status, pairs) { + const finalObject = {}; + for (const pair of pairs) { + const { key, value } = pair; + if (key.status === "aborted") + return parseUtil_INVALID; + if (value.status === "aborted") + return parseUtil_INVALID; + if (key.status === "dirty") + status.dirty(); + if (value.status === "dirty") + status.dirty(); + if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) { + finalObject[key.value] = value.value; + } + } + return { status: status.value, value: finalObject }; + } +} +const parseUtil_INVALID = Object.freeze({ + status: "aborted", +}); +const DIRTY = (value) => ({ status: "dirty", value }); +const OK = (value) => ({ status: "valid", value }); +const isAborted = (x) => x.status === "aborted"; +const isDirty = (x) => x.status === "dirty"; +const isValid = (x) => x.status === "valid"; +const isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise; + +;// CONCATENATED MODULE: ./node_modules/zod/v3/types.js + + + + + +class ParseInputLazyPath { + constructor(parent, value, path, key) { + this._cachedPath = []; + this.parent = parent; + this.data = value; + this._path = path; + this._key = key; + } + get path() { + if (!this._cachedPath.length) { + if (Array.isArray(this._key)) { + this._cachedPath.push(...this._path, ...this._key); + } + else { + this._cachedPath.push(...this._path, this._key); + } + } + return this._cachedPath; + } +} +const handleResult = (ctx, result) => { + if (isValid(result)) { + return { success: true, data: result.value }; + } + else { + if (!ctx.common.issues.length) { + throw new Error("Validation failed but no issues detected."); + } + return { + success: false, + get error() { + if (this._error) + return this._error; + const error = new ZodError(ctx.common.issues); + this._error = error; + return this._error; + }, + }; + } +}; +function processCreateParams(params) { + if (!params) + return {}; + const { errorMap, invalid_type_error, required_error, description } = params; + if (errorMap && (invalid_type_error || required_error)) { + throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`); + } + if (errorMap) + return { errorMap: errorMap, description }; + const customMap = (iss, ctx) => { + const { message } = params; + if (iss.code === "invalid_enum_value") { + return { message: message ?? ctx.defaultError }; + } + if (typeof ctx.data === "undefined") { + return { message: message ?? required_error ?? ctx.defaultError }; + } + if (iss.code !== "invalid_type") + return { message: ctx.defaultError }; + return { message: message ?? invalid_type_error ?? ctx.defaultError }; + }; + return { errorMap: customMap, description }; +} +class ZodType { + get description() { + return this._def.description; + } + _getType(input) { + return util_getParsedType(input.data); + } + _getOrReturnCtx(input, ctx) { + return (ctx || { + common: input.parent.common, + data: input.data, + parsedType: util_getParsedType(input.data), + schemaErrorMap: this._def.errorMap, + path: input.path, + parent: input.parent, + }); + } + _processInputParams(input) { + return { + status: new ParseStatus(), + ctx: { + common: input.parent.common, + data: input.data, + parsedType: util_getParsedType(input.data), + schemaErrorMap: this._def.errorMap, + path: input.path, + parent: input.parent, + }, + }; + } + _parseSync(input) { + const result = this._parse(input); + if (isAsync(result)) { + throw new Error("Synchronous parse encountered promise."); + } + return result; + } + _parseAsync(input) { + const result = this._parse(input); + return Promise.resolve(result); + } + parse(data, params) { + const result = this.safeParse(data, params); + if (result.success) + return result.data; + throw result.error; + } + safeParse(data, params) { + const ctx = { + common: { + issues: [], + async: params?.async ?? false, + contextualErrorMap: params?.errorMap, + }, + path: params?.path || [], + schemaErrorMap: this._def.errorMap, + parent: null, + data, + parsedType: util_getParsedType(data), + }; + const result = this._parseSync({ data, path: ctx.path, parent: ctx }); + return handleResult(ctx, result); + } + "~validate"(data) { + const ctx = { + common: { + issues: [], + async: !!this["~standard"].async, + }, + path: [], + schemaErrorMap: this._def.errorMap, + parent: null, + data, + parsedType: util_getParsedType(data), + }; + if (!this["~standard"].async) { + try { + const result = this._parseSync({ data, path: [], parent: ctx }); + return isValid(result) + ? { + value: result.value, + } + : { + issues: ctx.common.issues, + }; + } + catch (err) { + if (err?.message?.toLowerCase()?.includes("encountered")) { + this["~standard"].async = true; + } + ctx.common = { + issues: [], + async: true, + }; + } + } + return this._parseAsync({ data, path: [], parent: ctx }).then((result) => isValid(result) + ? { + value: result.value, + } + : { + issues: ctx.common.issues, + }); + } + async parseAsync(data, params) { + const result = await this.safeParseAsync(data, params); + if (result.success) + return result.data; + throw result.error; + } + async safeParseAsync(data, params) { + const ctx = { + common: { + issues: [], + contextualErrorMap: params?.errorMap, + async: true, + }, + path: params?.path || [], + schemaErrorMap: this._def.errorMap, + parent: null, + data, + parsedType: util_getParsedType(data), + }; + const maybeAsyncResult = this._parse({ data, path: ctx.path, parent: ctx }); + const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult)); + return handleResult(ctx, result); + } + refine(check, message) { + const getIssueProperties = (val) => { + if (typeof message === "string" || typeof message === "undefined") { + return { message }; + } + else if (typeof message === "function") { + return message(val); + } + else { + return message; + } + }; + return this._refinement((val, ctx) => { + const result = check(val); + const setError = () => ctx.addIssue({ + code: ZodIssueCode.custom, + ...getIssueProperties(val), + }); + if (typeof Promise !== "undefined" && result instanceof Promise) { + return result.then((data) => { + if (!data) { + setError(); + return false; + } + else { + return true; + } + }); + } + if (!result) { + setError(); + return false; + } + else { + return true; + } + }); + } + refinement(check, refinementData) { + return this._refinement((val, ctx) => { + if (!check(val)) { + ctx.addIssue(typeof refinementData === "function" ? refinementData(val, ctx) : refinementData); + return false; + } + else { + return true; + } + }); + } + _refinement(refinement) { + return new ZodEffects({ + schema: this, + typeName: ZodFirstPartyTypeKind.ZodEffects, + effect: { type: "refinement", refinement }, + }); + } + superRefine(refinement) { + return this._refinement(refinement); + } + constructor(def) { + /** Alias of safeParseAsync */ + this.spa = this.safeParseAsync; + this._def = def; + this.parse = this.parse.bind(this); + this.safeParse = this.safeParse.bind(this); + this.parseAsync = this.parseAsync.bind(this); + this.safeParseAsync = this.safeParseAsync.bind(this); + this.spa = this.spa.bind(this); + this.refine = this.refine.bind(this); + this.refinement = this.refinement.bind(this); + this.superRefine = this.superRefine.bind(this); + this.optional = this.optional.bind(this); + this.nullable = this.nullable.bind(this); + this.nullish = this.nullish.bind(this); + this.array = this.array.bind(this); + this.promise = this.promise.bind(this); + this.or = this.or.bind(this); + this.and = this.and.bind(this); + this.transform = this.transform.bind(this); + this.brand = this.brand.bind(this); + this.default = this.default.bind(this); + this.catch = this.catch.bind(this); + this.describe = this.describe.bind(this); + this.pipe = this.pipe.bind(this); + this.readonly = this.readonly.bind(this); + this.isNullable = this.isNullable.bind(this); + this.isOptional = this.isOptional.bind(this); + this["~standard"] = { + version: 1, + vendor: "zod", + validate: (data) => this["~validate"](data), + }; + } + optional() { + return ZodOptional.create(this, this._def); + } + nullable() { + return ZodNullable.create(this, this._def); + } + nullish() { + return this.nullable().optional(); + } + array() { + return ZodArray.create(this); + } + promise() { + return ZodPromise.create(this, this._def); + } + or(option) { + return ZodUnion.create([this, option], this._def); + } + and(incoming) { + return ZodIntersection.create(this, incoming, this._def); + } + transform(transform) { + return new ZodEffects({ + ...processCreateParams(this._def), + schema: this, + typeName: ZodFirstPartyTypeKind.ZodEffects, + effect: { type: "transform", transform }, + }); + } + default(def) { + const defaultValueFunc = typeof def === "function" ? def : () => def; + return new ZodDefault({ + ...processCreateParams(this._def), + innerType: this, + defaultValue: defaultValueFunc, + typeName: ZodFirstPartyTypeKind.ZodDefault, + }); + } + brand() { + return new ZodBranded({ + typeName: ZodFirstPartyTypeKind.ZodBranded, + type: this, + ...processCreateParams(this._def), + }); + } + catch(def) { + const catchValueFunc = typeof def === "function" ? def : () => def; + return new ZodCatch({ + ...processCreateParams(this._def), + innerType: this, + catchValue: catchValueFunc, + typeName: ZodFirstPartyTypeKind.ZodCatch, + }); + } + describe(description) { + const This = this.constructor; + return new This({ + ...this._def, + description, + }); + } + pipe(target) { + return ZodPipeline.create(this, target); + } + readonly() { + return ZodReadonly.create(this); + } + isOptional() { + return this.safeParse(undefined).success; + } + isNullable() { + return this.safeParse(null).success; + } +} +const cuidRegex = /^c[^\s-]{8,}$/i; +const cuid2Regex = /^[0-9a-z]+$/; +const ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/i; +// const uuidRegex = +// /^([a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[a-f0-9]{4}-[a-f0-9]{12}|00000000-0000-0000-0000-000000000000)$/i; +const uuidRegex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i; +const nanoidRegex = /^[a-z0-9_-]{21}$/i; +const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/; +const durationRegex = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/; +// from https://stackoverflow.com/a/46181/1550155 +// old version: too slow, didn't support unicode +// const emailRegex = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; +//old email regex +// const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i; +// eslint-disable-next-line +// const emailRegex = +// /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\])|(\[IPv6:(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))\])|([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])*(\.[A-Za-z]{2,})+))$/; +// const emailRegex = +// /^[a-zA-Z0-9\.\!\#\$\%\&\'\*\+\/\=\?\^\_\`\{\|\}\~\-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; +// const emailRegex = +// /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i; +const emailRegex = /^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i; +// const emailRegex = +// /^[a-z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9\-]+)*$/i; +// from https://thekevinscott.com/emojis-in-javascript/#writing-a-regular-expression +const _emojiRegex = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; +let emojiRegex; +// faster, simpler, safer +const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; +const ipv4CidrRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/; +// const ipv6Regex = +// /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/; +const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/; +const ipv6CidrRegex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; +// https://stackoverflow.com/questions/7860392/determine-if-string-is-in-base64-using-javascript +const base64Regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/; +// https://base64.guru/standards/base64url +const base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/; +// simple +// const dateRegexSource = `\\d{4}-\\d{2}-\\d{2}`; +// no leap year validation +// const dateRegexSource = `\\d{4}-((0[13578]|10|12)-31|(0[13-9]|1[0-2])-30|(0[1-9]|1[0-2])-(0[1-9]|1\\d|2\\d))`; +// with leap year validation +const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`; +const dateRegex = new RegExp(`^${dateRegexSource}$`); +function timeRegexSource(args) { + let secondsRegexSource = `[0-5]\\d`; + if (args.precision) { + secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`; + } + else if (args.precision == null) { + secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`; + } + const secondsQuantifier = args.precision ? "+" : "?"; // require seconds if precision is nonzero + return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`; +} +function timeRegex(args) { + return new RegExp(`^${timeRegexSource(args)}$`); +} +// Adapted from https://stackoverflow.com/a/3143231 +function datetimeRegex(args) { + let regex = `${dateRegexSource}T${timeRegexSource(args)}`; + const opts = []; + opts.push(args.local ? `Z?` : `Z`); + if (args.offset) + opts.push(`([+-]\\d{2}:?\\d{2})`); + regex = `${regex}(${opts.join("|")})`; + return new RegExp(`^${regex}$`); +} +function isValidIP(ip, version) { + if ((version === "v4" || !version) && ipv4Regex.test(ip)) { + return true; + } + if ((version === "v6" || !version) && ipv6Regex.test(ip)) { + return true; + } + return false; +} +function types_isValidJWT(jwt, alg) { + if (!jwtRegex.test(jwt)) + return false; + try { + const [header] = jwt.split("."); + if (!header) + return false; + // Convert base64url to base64 + const base64 = header + .replace(/-/g, "+") + .replace(/_/g, "/") + .padEnd(header.length + ((4 - (header.length % 4)) % 4), "="); + const decoded = JSON.parse(atob(base64)); + if (typeof decoded !== "object" || decoded === null) + return false; + if ("typ" in decoded && decoded?.typ !== "JWT") + return false; + if (!decoded.alg) + return false; + if (alg && decoded.alg !== alg) + return false; + return true; + } + catch { + return false; + } +} +function isValidCidr(ip, version) { + if ((version === "v4" || !version) && ipv4CidrRegex.test(ip)) { + return true; + } + if ((version === "v6" || !version) && ipv6CidrRegex.test(ip)) { + return true; + } + return false; +} +class ZodString extends ZodType { + _parse(input) { + if (this._def.coerce) { + input.data = String(input.data); + } + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.string) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.string, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + const status = new ParseStatus(); + let ctx = undefined; + for (const check of this._def.checks) { + if (check.kind === "min") { + if (input.data.length < check.value) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: check.value, + type: "string", + inclusive: true, + exact: false, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "max") { + if (input.data.length > check.value) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: check.value, + type: "string", + inclusive: true, + exact: false, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "length") { + const tooBig = input.data.length > check.value; + const tooSmall = input.data.length < check.value; + if (tooBig || tooSmall) { + ctx = this._getOrReturnCtx(input, ctx); + if (tooBig) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: check.value, + type: "string", + inclusive: true, + exact: true, + message: check.message, + }); + } + else if (tooSmall) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: check.value, + type: "string", + inclusive: true, + exact: true, + message: check.message, + }); + } + status.dirty(); + } + } + else if (check.kind === "email") { + if (!emailRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "email", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "emoji") { + if (!emojiRegex) { + emojiRegex = new RegExp(_emojiRegex, "u"); + } + if (!emojiRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "emoji", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "uuid") { + if (!uuidRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "uuid", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "nanoid") { + if (!nanoidRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "nanoid", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "cuid") { + if (!cuidRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "cuid", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "cuid2") { + if (!cuid2Regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "cuid2", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "ulid") { + if (!ulidRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "ulid", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "url") { + try { + new URL(input.data); + } + catch { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "url", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "regex") { + check.regex.lastIndex = 0; + const testResult = check.regex.test(input.data); + if (!testResult) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "regex", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "trim") { + input.data = input.data.trim(); + } + else if (check.kind === "includes") { + if (!input.data.includes(check.value, check.position)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: { includes: check.value, position: check.position }, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "toLowerCase") { + input.data = input.data.toLowerCase(); + } + else if (check.kind === "toUpperCase") { + input.data = input.data.toUpperCase(); + } + else if (check.kind === "startsWith") { + if (!input.data.startsWith(check.value)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: { startsWith: check.value }, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "endsWith") { + if (!input.data.endsWith(check.value)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: { endsWith: check.value }, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "datetime") { + const regex = datetimeRegex(check); + if (!regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: "datetime", + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "date") { + const regex = dateRegex; + if (!regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: "date", + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "time") { + const regex = timeRegex(check); + if (!regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_string, + validation: "time", + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "duration") { + if (!durationRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "duration", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "ip") { + if (!isValidIP(input.data, check.version)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "ip", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "jwt") { + if (!types_isValidJWT(input.data, check.alg)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "jwt", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "cidr") { + if (!isValidCidr(input.data, check.version)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "cidr", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "base64") { + if (!base64Regex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "base64", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "base64url") { + if (!base64urlRegex.test(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + validation: "base64url", + code: ZodIssueCode.invalid_string, + message: check.message, + }); + status.dirty(); + } + } + else { + util_util.assertNever(check); + } + } + return { status: status.value, value: input.data }; + } + _regex(regex, validation, message) { + return this.refinement((data) => regex.test(data), { + validation, + code: ZodIssueCode.invalid_string, + ...errorUtil.errToObj(message), + }); + } + _addCheck(check) { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, check], + }); + } + email(message) { + return this._addCheck({ kind: "email", ...errorUtil.errToObj(message) }); + } + url(message) { + return this._addCheck({ kind: "url", ...errorUtil.errToObj(message) }); + } + emoji(message) { + return this._addCheck({ kind: "emoji", ...errorUtil.errToObj(message) }); + } + uuid(message) { + return this._addCheck({ kind: "uuid", ...errorUtil.errToObj(message) }); + } + nanoid(message) { + return this._addCheck({ kind: "nanoid", ...errorUtil.errToObj(message) }); + } + cuid(message) { + return this._addCheck({ kind: "cuid", ...errorUtil.errToObj(message) }); + } + cuid2(message) { + return this._addCheck({ kind: "cuid2", ...errorUtil.errToObj(message) }); + } + ulid(message) { + return this._addCheck({ kind: "ulid", ...errorUtil.errToObj(message) }); + } + base64(message) { + return this._addCheck({ kind: "base64", ...errorUtil.errToObj(message) }); + } + base64url(message) { + // base64url encoding is a modification of base64 that can safely be used in URLs and filenames + return this._addCheck({ + kind: "base64url", + ...errorUtil.errToObj(message), + }); + } + jwt(options) { + return this._addCheck({ kind: "jwt", ...errorUtil.errToObj(options) }); + } + ip(options) { + return this._addCheck({ kind: "ip", ...errorUtil.errToObj(options) }); + } + cidr(options) { + return this._addCheck({ kind: "cidr", ...errorUtil.errToObj(options) }); + } + datetime(options) { + if (typeof options === "string") { + return this._addCheck({ + kind: "datetime", + precision: null, + offset: false, + local: false, + message: options, + }); + } + return this._addCheck({ + kind: "datetime", + precision: typeof options?.precision === "undefined" ? null : options?.precision, + offset: options?.offset ?? false, + local: options?.local ?? false, + ...errorUtil.errToObj(options?.message), + }); + } + date(message) { + return this._addCheck({ kind: "date", message }); + } + time(options) { + if (typeof options === "string") { + return this._addCheck({ + kind: "time", + precision: null, + message: options, + }); + } + return this._addCheck({ + kind: "time", + precision: typeof options?.precision === "undefined" ? null : options?.precision, + ...errorUtil.errToObj(options?.message), + }); + } + duration(message) { + return this._addCheck({ kind: "duration", ...errorUtil.errToObj(message) }); + } + regex(regex, message) { + return this._addCheck({ + kind: "regex", + regex: regex, + ...errorUtil.errToObj(message), + }); + } + includes(value, options) { + return this._addCheck({ + kind: "includes", + value: value, + position: options?.position, + ...errorUtil.errToObj(options?.message), + }); + } + startsWith(value, message) { + return this._addCheck({ + kind: "startsWith", + value: value, + ...errorUtil.errToObj(message), + }); + } + endsWith(value, message) { + return this._addCheck({ + kind: "endsWith", + value: value, + ...errorUtil.errToObj(message), + }); + } + min(minLength, message) { + return this._addCheck({ + kind: "min", + value: minLength, + ...errorUtil.errToObj(message), + }); + } + max(maxLength, message) { + return this._addCheck({ + kind: "max", + value: maxLength, + ...errorUtil.errToObj(message), + }); + } + length(len, message) { + return this._addCheck({ + kind: "length", + value: len, + ...errorUtil.errToObj(message), + }); + } + /** + * Equivalent to `.min(1)` + */ + nonempty(message) { + return this.min(1, errorUtil.errToObj(message)); + } + trim() { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, { kind: "trim" }], + }); + } + toLowerCase() { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, { kind: "toLowerCase" }], + }); + } + toUpperCase() { + return new ZodString({ + ...this._def, + checks: [...this._def.checks, { kind: "toUpperCase" }], + }); + } + get isDatetime() { + return !!this._def.checks.find((ch) => ch.kind === "datetime"); + } + get isDate() { + return !!this._def.checks.find((ch) => ch.kind === "date"); + } + get isTime() { + return !!this._def.checks.find((ch) => ch.kind === "time"); + } + get isDuration() { + return !!this._def.checks.find((ch) => ch.kind === "duration"); + } + get isEmail() { + return !!this._def.checks.find((ch) => ch.kind === "email"); + } + get isURL() { + return !!this._def.checks.find((ch) => ch.kind === "url"); + } + get isEmoji() { + return !!this._def.checks.find((ch) => ch.kind === "emoji"); + } + get isUUID() { + return !!this._def.checks.find((ch) => ch.kind === "uuid"); + } + get isNANOID() { + return !!this._def.checks.find((ch) => ch.kind === "nanoid"); + } + get isCUID() { + return !!this._def.checks.find((ch) => ch.kind === "cuid"); + } + get isCUID2() { + return !!this._def.checks.find((ch) => ch.kind === "cuid2"); + } + get isULID() { + return !!this._def.checks.find((ch) => ch.kind === "ulid"); + } + get isIP() { + return !!this._def.checks.find((ch) => ch.kind === "ip"); + } + get isCIDR() { + return !!this._def.checks.find((ch) => ch.kind === "cidr"); + } + get isBase64() { + return !!this._def.checks.find((ch) => ch.kind === "base64"); + } + get isBase64url() { + // base64url encoding is a modification of base64 that can safely be used in URLs and filenames + return !!this._def.checks.find((ch) => ch.kind === "base64url"); + } + get minLength() { + let min = null; + for (const ch of this._def.checks) { + if (ch.kind === "min") { + if (min === null || ch.value > min) + min = ch.value; + } + } + return min; + } + get maxLength() { + let max = null; + for (const ch of this._def.checks) { + if (ch.kind === "max") { + if (max === null || ch.value < max) + max = ch.value; + } + } + return max; + } +} +ZodString.create = (params) => { + return new ZodString({ + checks: [], + typeName: ZodFirstPartyTypeKind.ZodString, + coerce: params?.coerce ?? false, + ...processCreateParams(params), + }); +}; +// https://stackoverflow.com/questions/3966484/why-does-modulus-operator-return-fractional-number-in-javascript/31711034#31711034 +function types_floatSafeRemainder(val, step) { + const valDecCount = (val.toString().split(".")[1] || "").length; + const stepDecCount = (step.toString().split(".")[1] || "").length; + const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount; + const valInt = Number.parseInt(val.toFixed(decCount).replace(".", "")); + const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", "")); + return (valInt % stepInt) / 10 ** decCount; +} +class ZodNumber extends ZodType { + constructor() { + super(...arguments); + this.min = this.gte; + this.max = this.lte; + this.step = this.multipleOf; + } + _parse(input) { + if (this._def.coerce) { + input.data = Number(input.data); + } + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.number) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.number, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + let ctx = undefined; + const status = new ParseStatus(); + for (const check of this._def.checks) { + if (check.kind === "int") { + if (!util_util.isInteger(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: "integer", + received: "float", + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "min") { + const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value; + if (tooSmall) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: check.value, + type: "number", + inclusive: check.inclusive, + exact: false, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "max") { + const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value; + if (tooBig) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: check.value, + type: "number", + inclusive: check.inclusive, + exact: false, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "multipleOf") { + if (types_floatSafeRemainder(input.data, check.value) !== 0) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.not_multiple_of, + multipleOf: check.value, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "finite") { + if (!Number.isFinite(input.data)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.not_finite, + message: check.message, + }); + status.dirty(); + } + } + else { + util_util.assertNever(check); + } + } + return { status: status.value, value: input.data }; + } + gte(value, message) { + return this.setLimit("min", value, true, errorUtil.toString(message)); + } + gt(value, message) { + return this.setLimit("min", value, false, errorUtil.toString(message)); + } + lte(value, message) { + return this.setLimit("max", value, true, errorUtil.toString(message)); + } + lt(value, message) { + return this.setLimit("max", value, false, errorUtil.toString(message)); + } + setLimit(kind, value, inclusive, message) { + return new ZodNumber({ + ...this._def, + checks: [ + ...this._def.checks, + { + kind, + value, + inclusive, + message: errorUtil.toString(message), + }, + ], + }); + } + _addCheck(check) { + return new ZodNumber({ + ...this._def, + checks: [...this._def.checks, check], + }); + } + int(message) { + return this._addCheck({ + kind: "int", + message: errorUtil.toString(message), + }); + } + positive(message) { + return this._addCheck({ + kind: "min", + value: 0, + inclusive: false, + message: errorUtil.toString(message), + }); + } + negative(message) { + return this._addCheck({ + kind: "max", + value: 0, + inclusive: false, + message: errorUtil.toString(message), + }); + } + nonpositive(message) { + return this._addCheck({ + kind: "max", + value: 0, + inclusive: true, + message: errorUtil.toString(message), + }); + } + nonnegative(message) { + return this._addCheck({ + kind: "min", + value: 0, + inclusive: true, + message: errorUtil.toString(message), + }); + } + multipleOf(value, message) { + return this._addCheck({ + kind: "multipleOf", + value: value, + message: errorUtil.toString(message), + }); + } + finite(message) { + return this._addCheck({ + kind: "finite", + message: errorUtil.toString(message), + }); + } + safe(message) { + return this._addCheck({ + kind: "min", + inclusive: true, + value: Number.MIN_SAFE_INTEGER, + message: errorUtil.toString(message), + })._addCheck({ + kind: "max", + inclusive: true, + value: Number.MAX_SAFE_INTEGER, + message: errorUtil.toString(message), + }); + } + get minValue() { + let min = null; + for (const ch of this._def.checks) { + if (ch.kind === "min") { + if (min === null || ch.value > min) + min = ch.value; + } + } + return min; + } + get maxValue() { + let max = null; + for (const ch of this._def.checks) { + if (ch.kind === "max") { + if (max === null || ch.value < max) + max = ch.value; + } + } + return max; + } + get isInt() { + return !!this._def.checks.find((ch) => ch.kind === "int" || (ch.kind === "multipleOf" && util_util.isInteger(ch.value))); + } + get isFinite() { + let max = null; + let min = null; + for (const ch of this._def.checks) { + if (ch.kind === "finite" || ch.kind === "int" || ch.kind === "multipleOf") { + return true; + } + else if (ch.kind === "min") { + if (min === null || ch.value > min) + min = ch.value; + } + else if (ch.kind === "max") { + if (max === null || ch.value < max) + max = ch.value; + } + } + return Number.isFinite(min) && Number.isFinite(max); + } +} +ZodNumber.create = (params) => { + return new ZodNumber({ + checks: [], + typeName: ZodFirstPartyTypeKind.ZodNumber, + coerce: params?.coerce || false, + ...processCreateParams(params), + }); +}; +class ZodBigInt extends ZodType { + constructor() { + super(...arguments); + this.min = this.gte; + this.max = this.lte; + } + _parse(input) { + if (this._def.coerce) { + try { + input.data = BigInt(input.data); + } + catch { + return this._getInvalidInput(input); + } + } + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.bigint) { + return this._getInvalidInput(input); + } + let ctx = undefined; + const status = new ParseStatus(); + for (const check of this._def.checks) { + if (check.kind === "min") { + const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value; + if (tooSmall) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + type: "bigint", + minimum: check.value, + inclusive: check.inclusive, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "max") { + const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value; + if (tooBig) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + type: "bigint", + maximum: check.value, + inclusive: check.inclusive, + message: check.message, + }); + status.dirty(); + } + } + else if (check.kind === "multipleOf") { + if (input.data % check.value !== BigInt(0)) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.not_multiple_of, + multipleOf: check.value, + message: check.message, + }); + status.dirty(); + } + } + else { + util_util.assertNever(check); + } + } + return { status: status.value, value: input.data }; + } + _getInvalidInput(input) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.bigint, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + gte(value, message) { + return this.setLimit("min", value, true, errorUtil.toString(message)); + } + gt(value, message) { + return this.setLimit("min", value, false, errorUtil.toString(message)); + } + lte(value, message) { + return this.setLimit("max", value, true, errorUtil.toString(message)); + } + lt(value, message) { + return this.setLimit("max", value, false, errorUtil.toString(message)); + } + setLimit(kind, value, inclusive, message) { + return new ZodBigInt({ + ...this._def, + checks: [ + ...this._def.checks, + { + kind, + value, + inclusive, + message: errorUtil.toString(message), + }, + ], + }); + } + _addCheck(check) { + return new ZodBigInt({ + ...this._def, + checks: [...this._def.checks, check], + }); + } + positive(message) { + return this._addCheck({ + kind: "min", + value: BigInt(0), + inclusive: false, + message: errorUtil.toString(message), + }); + } + negative(message) { + return this._addCheck({ + kind: "max", + value: BigInt(0), + inclusive: false, + message: errorUtil.toString(message), + }); + } + nonpositive(message) { + return this._addCheck({ + kind: "max", + value: BigInt(0), + inclusive: true, + message: errorUtil.toString(message), + }); + } + nonnegative(message) { + return this._addCheck({ + kind: "min", + value: BigInt(0), + inclusive: true, + message: errorUtil.toString(message), + }); + } + multipleOf(value, message) { + return this._addCheck({ + kind: "multipleOf", + value, + message: errorUtil.toString(message), + }); + } + get minValue() { + let min = null; + for (const ch of this._def.checks) { + if (ch.kind === "min") { + if (min === null || ch.value > min) + min = ch.value; + } + } + return min; + } + get maxValue() { + let max = null; + for (const ch of this._def.checks) { + if (ch.kind === "max") { + if (max === null || ch.value < max) + max = ch.value; + } + } + return max; + } +} +ZodBigInt.create = (params) => { + return new ZodBigInt({ + checks: [], + typeName: ZodFirstPartyTypeKind.ZodBigInt, + coerce: params?.coerce ?? false, + ...processCreateParams(params), + }); +}; +class ZodBoolean extends ZodType { + _parse(input) { + if (this._def.coerce) { + input.data = Boolean(input.data); + } + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.boolean) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.boolean, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + return OK(input.data); + } +} +ZodBoolean.create = (params) => { + return new ZodBoolean({ + typeName: ZodFirstPartyTypeKind.ZodBoolean, + coerce: params?.coerce || false, + ...processCreateParams(params), + }); +}; +class ZodDate extends ZodType { + _parse(input) { + if (this._def.coerce) { + input.data = new Date(input.data); + } + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.date) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.date, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + if (Number.isNaN(input.data.getTime())) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_date, + }); + return parseUtil_INVALID; + } + const status = new ParseStatus(); + let ctx = undefined; + for (const check of this._def.checks) { + if (check.kind === "min") { + if (input.data.getTime() < check.value) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + message: check.message, + inclusive: true, + exact: false, + minimum: check.value, + type: "date", + }); + status.dirty(); + } + } + else if (check.kind === "max") { + if (input.data.getTime() > check.value) { + ctx = this._getOrReturnCtx(input, ctx); + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + message: check.message, + inclusive: true, + exact: false, + maximum: check.value, + type: "date", + }); + status.dirty(); + } + } + else { + util_util.assertNever(check); + } + } + return { + status: status.value, + value: new Date(input.data.getTime()), + }; + } + _addCheck(check) { + return new ZodDate({ + ...this._def, + checks: [...this._def.checks, check], + }); + } + min(minDate, message) { + return this._addCheck({ + kind: "min", + value: minDate.getTime(), + message: errorUtil.toString(message), + }); + } + max(maxDate, message) { + return this._addCheck({ + kind: "max", + value: maxDate.getTime(), + message: errorUtil.toString(message), + }); + } + get minDate() { + let min = null; + for (const ch of this._def.checks) { + if (ch.kind === "min") { + if (min === null || ch.value > min) + min = ch.value; + } + } + return min != null ? new Date(min) : null; + } + get maxDate() { + let max = null; + for (const ch of this._def.checks) { + if (ch.kind === "max") { + if (max === null || ch.value < max) + max = ch.value; + } + } + return max != null ? new Date(max) : null; + } +} +ZodDate.create = (params) => { + return new ZodDate({ + checks: [], + coerce: params?.coerce || false, + typeName: ZodFirstPartyTypeKind.ZodDate, + ...processCreateParams(params), + }); +}; +class ZodSymbol extends ZodType { + _parse(input) { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.symbol) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.symbol, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + return OK(input.data); + } +} +ZodSymbol.create = (params) => { + return new ZodSymbol({ + typeName: ZodFirstPartyTypeKind.ZodSymbol, + ...processCreateParams(params), + }); +}; +class ZodUndefined extends ZodType { + _parse(input) { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.undefined) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.undefined, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + return OK(input.data); + } +} +ZodUndefined.create = (params) => { + return new ZodUndefined({ + typeName: ZodFirstPartyTypeKind.ZodUndefined, + ...processCreateParams(params), + }); +}; +class ZodNull extends ZodType { + _parse(input) { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.null) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.null, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + return OK(input.data); + } +} +ZodNull.create = (params) => { + return new ZodNull({ + typeName: ZodFirstPartyTypeKind.ZodNull, + ...processCreateParams(params), + }); +}; +class ZodAny extends ZodType { + constructor() { + super(...arguments); + // to prevent instances of other classes from extending ZodAny. this causes issues with catchall in ZodObject. + this._any = true; + } + _parse(input) { + return OK(input.data); + } +} +ZodAny.create = (params) => { + return new ZodAny({ + typeName: ZodFirstPartyTypeKind.ZodAny, + ...processCreateParams(params), + }); +}; +class ZodUnknown extends ZodType { + constructor() { + super(...arguments); + // required + this._unknown = true; + } + _parse(input) { + return OK(input.data); + } +} +ZodUnknown.create = (params) => { + return new ZodUnknown({ + typeName: ZodFirstPartyTypeKind.ZodUnknown, + ...processCreateParams(params), + }); +}; +class ZodNever extends ZodType { + _parse(input) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.never, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } +} +ZodNever.create = (params) => { + return new ZodNever({ + typeName: ZodFirstPartyTypeKind.ZodNever, + ...processCreateParams(params), + }); +}; +class ZodVoid extends ZodType { + _parse(input) { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.undefined) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.void, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + return OK(input.data); + } +} +ZodVoid.create = (params) => { + return new ZodVoid({ + typeName: ZodFirstPartyTypeKind.ZodVoid, + ...processCreateParams(params), + }); +}; +class ZodArray extends ZodType { + _parse(input) { + const { ctx, status } = this._processInputParams(input); + const def = this._def; + if (ctx.parsedType !== ZodParsedType.array) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.array, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + if (def.exactLength !== null) { + const tooBig = ctx.data.length > def.exactLength.value; + const tooSmall = ctx.data.length < def.exactLength.value; + if (tooBig || tooSmall) { + addIssueToContext(ctx, { + code: tooBig ? ZodIssueCode.too_big : ZodIssueCode.too_small, + minimum: (tooSmall ? def.exactLength.value : undefined), + maximum: (tooBig ? def.exactLength.value : undefined), + type: "array", + inclusive: true, + exact: true, + message: def.exactLength.message, + }); + status.dirty(); + } + } + if (def.minLength !== null) { + if (ctx.data.length < def.minLength.value) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: def.minLength.value, + type: "array", + inclusive: true, + exact: false, + message: def.minLength.message, + }); + status.dirty(); + } + } + if (def.maxLength !== null) { + if (ctx.data.length > def.maxLength.value) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: def.maxLength.value, + type: "array", + inclusive: true, + exact: false, + message: def.maxLength.message, + }); + status.dirty(); + } + } + if (ctx.common.async) { + return Promise.all([...ctx.data].map((item, i) => { + return def.type._parseAsync(new ParseInputLazyPath(ctx, item, ctx.path, i)); + })).then((result) => { + return ParseStatus.mergeArray(status, result); + }); + } + const result = [...ctx.data].map((item, i) => { + return def.type._parseSync(new ParseInputLazyPath(ctx, item, ctx.path, i)); + }); + return ParseStatus.mergeArray(status, result); + } + get element() { + return this._def.type; + } + min(minLength, message) { + return new ZodArray({ + ...this._def, + minLength: { value: minLength, message: errorUtil.toString(message) }, + }); + } + max(maxLength, message) { + return new ZodArray({ + ...this._def, + maxLength: { value: maxLength, message: errorUtil.toString(message) }, + }); + } + length(len, message) { + return new ZodArray({ + ...this._def, + exactLength: { value: len, message: errorUtil.toString(message) }, + }); + } + nonempty(message) { + return this.min(1, message); + } +} +ZodArray.create = (schema, params) => { + return new ZodArray({ + type: schema, + minLength: null, + maxLength: null, + exactLength: null, + typeName: ZodFirstPartyTypeKind.ZodArray, + ...processCreateParams(params), + }); +}; +function deepPartialify(schema) { + if (schema instanceof ZodObject) { + const newShape = {}; + for (const key in schema.shape) { + const fieldSchema = schema.shape[key]; + newShape[key] = ZodOptional.create(deepPartialify(fieldSchema)); + } + return new ZodObject({ + ...schema._def, + shape: () => newShape, + }); + } + else if (schema instanceof ZodArray) { + return new ZodArray({ + ...schema._def, + type: deepPartialify(schema.element), + }); + } + else if (schema instanceof ZodOptional) { + return ZodOptional.create(deepPartialify(schema.unwrap())); + } + else if (schema instanceof ZodNullable) { + return ZodNullable.create(deepPartialify(schema.unwrap())); + } + else if (schema instanceof ZodTuple) { + return ZodTuple.create(schema.items.map((item) => deepPartialify(item))); + } + else { + return schema; + } +} +class ZodObject extends ZodType { + constructor() { + super(...arguments); + this._cached = null; + /** + * @deprecated In most cases, this is no longer needed - unknown properties are now silently stripped. + * If you want to pass through unknown properties, use `.passthrough()` instead. + */ + this.nonstrict = this.passthrough; + // extend< + // Augmentation extends ZodRawShape, + // NewOutput extends util.flatten<{ + // [k in keyof Augmentation | keyof Output]: k extends keyof Augmentation + // ? Augmentation[k]["_output"] + // : k extends keyof Output + // ? Output[k] + // : never; + // }>, + // NewInput extends util.flatten<{ + // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation + // ? Augmentation[k]["_input"] + // : k extends keyof Input + // ? Input[k] + // : never; + // }> + // >( + // augmentation: Augmentation + // ): ZodObject< + // extendShape, + // UnknownKeys, + // Catchall, + // NewOutput, + // NewInput + // > { + // return new ZodObject({ + // ...this._def, + // shape: () => ({ + // ...this._def.shape(), + // ...augmentation, + // }), + // }) as any; + // } + /** + * @deprecated Use `.extend` instead + * */ + this.augment = this.extend; + } + _getCached() { + if (this._cached !== null) + return this._cached; + const shape = this._def.shape(); + const keys = util_util.objectKeys(shape); + this._cached = { shape, keys }; + return this._cached; + } + _parse(input) { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.object) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.object, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + const { status, ctx } = this._processInputParams(input); + const { shape, keys: shapeKeys } = this._getCached(); + const extraKeys = []; + if (!(this._def.catchall instanceof ZodNever && this._def.unknownKeys === "strip")) { + for (const key in ctx.data) { + if (!shapeKeys.includes(key)) { + extraKeys.push(key); + } + } + } + const pairs = []; + for (const key of shapeKeys) { + const keyValidator = shape[key]; + const value = ctx.data[key]; + pairs.push({ + key: { status: "valid", value: key }, + value: keyValidator._parse(new ParseInputLazyPath(ctx, value, ctx.path, key)), + alwaysSet: key in ctx.data, + }); + } + if (this._def.catchall instanceof ZodNever) { + const unknownKeys = this._def.unknownKeys; + if (unknownKeys === "passthrough") { + for (const key of extraKeys) { + pairs.push({ + key: { status: "valid", value: key }, + value: { status: "valid", value: ctx.data[key] }, + }); + } + } + else if (unknownKeys === "strict") { + if (extraKeys.length > 0) { + addIssueToContext(ctx, { + code: ZodIssueCode.unrecognized_keys, + keys: extraKeys, + }); + status.dirty(); + } + } + else if (unknownKeys === "strip") { + } + else { + throw new Error(`Internal ZodObject error: invalid unknownKeys value.`); + } + } + else { + // run catchall validation + const catchall = this._def.catchall; + for (const key of extraKeys) { + const value = ctx.data[key]; + pairs.push({ + key: { status: "valid", value: key }, + value: catchall._parse(new ParseInputLazyPath(ctx, value, ctx.path, key) //, ctx.child(key), value, getParsedType(value) + ), + alwaysSet: key in ctx.data, + }); + } + } + if (ctx.common.async) { + return Promise.resolve() + .then(async () => { + const syncPairs = []; + for (const pair of pairs) { + const key = await pair.key; + const value = await pair.value; + syncPairs.push({ + key, + value, + alwaysSet: pair.alwaysSet, + }); + } + return syncPairs; + }) + .then((syncPairs) => { + return ParseStatus.mergeObjectSync(status, syncPairs); + }); + } + else { + return ParseStatus.mergeObjectSync(status, pairs); + } + } + get shape() { + return this._def.shape(); + } + strict(message) { + errorUtil.errToObj; + return new ZodObject({ + ...this._def, + unknownKeys: "strict", + ...(message !== undefined + ? { + errorMap: (issue, ctx) => { + const defaultError = this._def.errorMap?.(issue, ctx).message ?? ctx.defaultError; + if (issue.code === "unrecognized_keys") + return { + message: errorUtil.errToObj(message).message ?? defaultError, + }; + return { + message: defaultError, + }; + }, + } + : {}), + }); + } + strip() { + return new ZodObject({ + ...this._def, + unknownKeys: "strip", + }); + } + passthrough() { + return new ZodObject({ + ...this._def, + unknownKeys: "passthrough", + }); + } + // const AugmentFactory = + // (def: Def) => + // ( + // augmentation: Augmentation + // ): ZodObject< + // extendShape, Augmentation>, + // Def["unknownKeys"], + // Def["catchall"] + // > => { + // return new ZodObject({ + // ...def, + // shape: () => ({ + // ...def.shape(), + // ...augmentation, + // }), + // }) as any; + // }; + extend(augmentation) { + return new ZodObject({ + ...this._def, + shape: () => ({ + ...this._def.shape(), + ...augmentation, + }), + }); + } + /** + * Prior to zod@1.0.12 there was a bug in the + * inferred type of merged objects. Please + * upgrade if you are experiencing issues. + */ + merge(merging) { + const merged = new ZodObject({ + unknownKeys: merging._def.unknownKeys, + catchall: merging._def.catchall, + shape: () => ({ + ...this._def.shape(), + ...merging._def.shape(), + }), + typeName: ZodFirstPartyTypeKind.ZodObject, + }); + return merged; + } + // merge< + // Incoming extends AnyZodObject, + // Augmentation extends Incoming["shape"], + // NewOutput extends { + // [k in keyof Augmentation | keyof Output]: k extends keyof Augmentation + // ? Augmentation[k]["_output"] + // : k extends keyof Output + // ? Output[k] + // : never; + // }, + // NewInput extends { + // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation + // ? Augmentation[k]["_input"] + // : k extends keyof Input + // ? Input[k] + // : never; + // } + // >( + // merging: Incoming + // ): ZodObject< + // extendShape>, + // Incoming["_def"]["unknownKeys"], + // Incoming["_def"]["catchall"], + // NewOutput, + // NewInput + // > { + // const merged: any = new ZodObject({ + // unknownKeys: merging._def.unknownKeys, + // catchall: merging._def.catchall, + // shape: () => + // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), + // typeName: ZodFirstPartyTypeKind.ZodObject, + // }) as any; + // return merged; + // } + setKey(key, schema) { + return this.augment({ [key]: schema }); + } + // merge( + // merging: Incoming + // ): //ZodObject = (merging) => { + // ZodObject< + // extendShape>, + // Incoming["_def"]["unknownKeys"], + // Incoming["_def"]["catchall"] + // > { + // // const mergedShape = objectUtil.mergeShapes( + // // this._def.shape(), + // // merging._def.shape() + // // ); + // const merged: any = new ZodObject({ + // unknownKeys: merging._def.unknownKeys, + // catchall: merging._def.catchall, + // shape: () => + // objectUtil.mergeShapes(this._def.shape(), merging._def.shape()), + // typeName: ZodFirstPartyTypeKind.ZodObject, + // }) as any; + // return merged; + // } + catchall(index) { + return new ZodObject({ + ...this._def, + catchall: index, + }); + } + pick(mask) { + const shape = {}; + for (const key of util_util.objectKeys(mask)) { + if (mask[key] && this.shape[key]) { + shape[key] = this.shape[key]; + } + } + return new ZodObject({ + ...this._def, + shape: () => shape, + }); + } + omit(mask) { + const shape = {}; + for (const key of util_util.objectKeys(this.shape)) { + if (!mask[key]) { + shape[key] = this.shape[key]; + } + } + return new ZodObject({ + ...this._def, + shape: () => shape, + }); + } + /** + * @deprecated + */ + deepPartial() { + return deepPartialify(this); + } + partial(mask) { + const newShape = {}; + for (const key of util_util.objectKeys(this.shape)) { + const fieldSchema = this.shape[key]; + if (mask && !mask[key]) { + newShape[key] = fieldSchema; + } + else { + newShape[key] = fieldSchema.optional(); + } + } + return new ZodObject({ + ...this._def, + shape: () => newShape, + }); + } + required(mask) { + const newShape = {}; + for (const key of util_util.objectKeys(this.shape)) { + if (mask && !mask[key]) { + newShape[key] = this.shape[key]; + } + else { + const fieldSchema = this.shape[key]; + let newField = fieldSchema; + while (newField instanceof ZodOptional) { + newField = newField._def.innerType; + } + newShape[key] = newField; + } + } + return new ZodObject({ + ...this._def, + shape: () => newShape, + }); + } + keyof() { + return createZodEnum(util_util.objectKeys(this.shape)); + } +} +ZodObject.create = (shape, params) => { + return new ZodObject({ + shape: () => shape, + unknownKeys: "strip", + catchall: ZodNever.create(), + typeName: ZodFirstPartyTypeKind.ZodObject, + ...processCreateParams(params), + }); +}; +ZodObject.strictCreate = (shape, params) => { + return new ZodObject({ + shape: () => shape, + unknownKeys: "strict", + catchall: ZodNever.create(), + typeName: ZodFirstPartyTypeKind.ZodObject, + ...processCreateParams(params), + }); +}; +ZodObject.lazycreate = (shape, params) => { + return new ZodObject({ + shape, + unknownKeys: "strip", + catchall: ZodNever.create(), + typeName: ZodFirstPartyTypeKind.ZodObject, + ...processCreateParams(params), + }); +}; +class ZodUnion extends ZodType { + _parse(input) { + const { ctx } = this._processInputParams(input); + const options = this._def.options; + function handleResults(results) { + // return first issue-free validation if it exists + for (const result of results) { + if (result.result.status === "valid") { + return result.result; + } + } + for (const result of results) { + if (result.result.status === "dirty") { + // add issues from dirty option + ctx.common.issues.push(...result.ctx.common.issues); + return result.result; + } + } + // return invalid + const unionErrors = results.map((result) => new ZodError(result.ctx.common.issues)); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_union, + unionErrors, + }); + return parseUtil_INVALID; + } + if (ctx.common.async) { + return Promise.all(options.map(async (option) => { + const childCtx = { + ...ctx, + common: { + ...ctx.common, + issues: [], + }, + parent: null, + }; + return { + result: await option._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: childCtx, + }), + ctx: childCtx, + }; + })).then(handleResults); + } + else { + let dirty = undefined; + const issues = []; + for (const option of options) { + const childCtx = { + ...ctx, + common: { + ...ctx.common, + issues: [], + }, + parent: null, + }; + const result = option._parseSync({ + data: ctx.data, + path: ctx.path, + parent: childCtx, + }); + if (result.status === "valid") { + return result; + } + else if (result.status === "dirty" && !dirty) { + dirty = { result, ctx: childCtx }; + } + if (childCtx.common.issues.length) { + issues.push(childCtx.common.issues); + } + } + if (dirty) { + ctx.common.issues.push(...dirty.ctx.common.issues); + return dirty.result; + } + const unionErrors = issues.map((issues) => new ZodError(issues)); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_union, + unionErrors, + }); + return parseUtil_INVALID; + } + } + get options() { + return this._def.options; + } +} +ZodUnion.create = (types, params) => { + return new ZodUnion({ + options: types, + typeName: ZodFirstPartyTypeKind.ZodUnion, + ...processCreateParams(params), + }); +}; +///////////////////////////////////////////////////// +///////////////////////////////////////////////////// +////////// ////////// +////////// ZodDiscriminatedUnion ////////// +////////// ////////// +///////////////////////////////////////////////////// +///////////////////////////////////////////////////// +const getDiscriminator = (type) => { + if (type instanceof ZodLazy) { + return getDiscriminator(type.schema); + } + else if (type instanceof ZodEffects) { + return getDiscriminator(type.innerType()); + } + else if (type instanceof ZodLiteral) { + return [type.value]; + } + else if (type instanceof ZodEnum) { + return type.options; + } + else if (type instanceof ZodNativeEnum) { + // eslint-disable-next-line ban/ban + return util_util.objectValues(type.enum); + } + else if (type instanceof ZodDefault) { + return getDiscriminator(type._def.innerType); + } + else if (type instanceof ZodUndefined) { + return [undefined]; + } + else if (type instanceof ZodNull) { + return [null]; + } + else if (type instanceof ZodOptional) { + return [undefined, ...getDiscriminator(type.unwrap())]; + } + else if (type instanceof ZodNullable) { + return [null, ...getDiscriminator(type.unwrap())]; + } + else if (type instanceof ZodBranded) { + return getDiscriminator(type.unwrap()); + } + else if (type instanceof ZodReadonly) { + return getDiscriminator(type.unwrap()); + } + else if (type instanceof ZodCatch) { + return getDiscriminator(type._def.innerType); + } + else { + return []; + } +}; +class ZodDiscriminatedUnion extends ZodType { + _parse(input) { + const { ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.object) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.object, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + const discriminator = this.discriminator; + const discriminatorValue = ctx.data[discriminator]; + const option = this.optionsMap.get(discriminatorValue); + if (!option) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_union_discriminator, + options: Array.from(this.optionsMap.keys()), + path: [discriminator], + }); + return parseUtil_INVALID; + } + if (ctx.common.async) { + return option._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + } + else { + return option._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + } + } + get discriminator() { + return this._def.discriminator; + } + get options() { + return this._def.options; + } + get optionsMap() { + return this._def.optionsMap; + } + /** + * The constructor of the discriminated union schema. Its behaviour is very similar to that of the normal z.union() constructor. + * However, it only allows a union of objects, all of which need to share a discriminator property. This property must + * have a different value for each object in the union. + * @param discriminator the name of the discriminator property + * @param types an array of object schemas + * @param params + */ + static create(discriminator, options, params) { + // Get all the valid discriminator values + const optionsMap = new Map(); + // try { + for (const type of options) { + const discriminatorValues = getDiscriminator(type.shape[discriminator]); + if (!discriminatorValues.length) { + throw new Error(`A discriminator value for key \`${discriminator}\` could not be extracted from all schema options`); + } + for (const value of discriminatorValues) { + if (optionsMap.has(value)) { + throw new Error(`Discriminator property ${String(discriminator)} has duplicate value ${String(value)}`); + } + optionsMap.set(value, type); + } + } + return new ZodDiscriminatedUnion({ + typeName: ZodFirstPartyTypeKind.ZodDiscriminatedUnion, + discriminator, + options, + optionsMap, + ...processCreateParams(params), + }); + } +} +function types_mergeValues(a, b) { + const aType = util_getParsedType(a); + const bType = util_getParsedType(b); + if (a === b) { + return { valid: true, data: a }; + } + else if (aType === ZodParsedType.object && bType === ZodParsedType.object) { + const bKeys = util_util.objectKeys(b); + const sharedKeys = util_util.objectKeys(a).filter((key) => bKeys.indexOf(key) !== -1); + const newObj = { ...a, ...b }; + for (const key of sharedKeys) { + const sharedValue = types_mergeValues(a[key], b[key]); + if (!sharedValue.valid) { + return { valid: false }; + } + newObj[key] = sharedValue.data; + } + return { valid: true, data: newObj }; + } + else if (aType === ZodParsedType.array && bType === ZodParsedType.array) { + if (a.length !== b.length) { + return { valid: false }; + } + const newArray = []; + for (let index = 0; index < a.length; index++) { + const itemA = a[index]; + const itemB = b[index]; + const sharedValue = types_mergeValues(itemA, itemB); + if (!sharedValue.valid) { + return { valid: false }; + } + newArray.push(sharedValue.data); + } + return { valid: true, data: newArray }; + } + else if (aType === ZodParsedType.date && bType === ZodParsedType.date && +a === +b) { + return { valid: true, data: a }; + } + else { + return { valid: false }; + } +} +class ZodIntersection extends ZodType { + _parse(input) { + const { status, ctx } = this._processInputParams(input); + const handleParsed = (parsedLeft, parsedRight) => { + if (isAborted(parsedLeft) || isAborted(parsedRight)) { + return parseUtil_INVALID; + } + const merged = types_mergeValues(parsedLeft.value, parsedRight.value); + if (!merged.valid) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_intersection_types, + }); + return parseUtil_INVALID; + } + if (isDirty(parsedLeft) || isDirty(parsedRight)) { + status.dirty(); + } + return { status: status.value, value: merged.data }; + }; + if (ctx.common.async) { + return Promise.all([ + this._def.left._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }), + this._def.right._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }), + ]).then(([left, right]) => handleParsed(left, right)); + } + else { + return handleParsed(this._def.left._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }), this._def.right._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + })); + } + } +} +ZodIntersection.create = (left, right, params) => { + return new ZodIntersection({ + left: left, + right: right, + typeName: ZodFirstPartyTypeKind.ZodIntersection, + ...processCreateParams(params), + }); +}; +// type ZodTupleItems = [ZodTypeAny, ...ZodTypeAny[]]; +class ZodTuple extends ZodType { + _parse(input) { + const { status, ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.array) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.array, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + if (ctx.data.length < this._def.items.length) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: this._def.items.length, + inclusive: true, + exact: false, + type: "array", + }); + return parseUtil_INVALID; + } + const rest = this._def.rest; + if (!rest && ctx.data.length > this._def.items.length) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: this._def.items.length, + inclusive: true, + exact: false, + type: "array", + }); + status.dirty(); + } + const items = [...ctx.data] + .map((item, itemIndex) => { + const schema = this._def.items[itemIndex] || this._def.rest; + if (!schema) + return null; + return schema._parse(new ParseInputLazyPath(ctx, item, ctx.path, itemIndex)); + }) + .filter((x) => !!x); // filter nulls + if (ctx.common.async) { + return Promise.all(items).then((results) => { + return ParseStatus.mergeArray(status, results); + }); + } + else { + return ParseStatus.mergeArray(status, items); + } + } + get items() { + return this._def.items; + } + rest(rest) { + return new ZodTuple({ + ...this._def, + rest, + }); + } +} +ZodTuple.create = (schemas, params) => { + if (!Array.isArray(schemas)) { + throw new Error("You must pass an array of schemas to z.tuple([ ... ])"); + } + return new ZodTuple({ + items: schemas, + typeName: ZodFirstPartyTypeKind.ZodTuple, + rest: null, + ...processCreateParams(params), + }); +}; +class ZodRecord extends ZodType { + get keySchema() { + return this._def.keyType; + } + get valueSchema() { + return this._def.valueType; + } + _parse(input) { + const { status, ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.object) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.object, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + const pairs = []; + const keyType = this._def.keyType; + const valueType = this._def.valueType; + for (const key in ctx.data) { + pairs.push({ + key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, key)), + value: valueType._parse(new ParseInputLazyPath(ctx, ctx.data[key], ctx.path, key)), + alwaysSet: key in ctx.data, + }); + } + if (ctx.common.async) { + return ParseStatus.mergeObjectAsync(status, pairs); + } + else { + return ParseStatus.mergeObjectSync(status, pairs); + } + } + get element() { + return this._def.valueType; + } + static create(first, second, third) { + if (second instanceof ZodType) { + return new ZodRecord({ + keyType: first, + valueType: second, + typeName: ZodFirstPartyTypeKind.ZodRecord, + ...processCreateParams(third), + }); + } + return new ZodRecord({ + keyType: ZodString.create(), + valueType: first, + typeName: ZodFirstPartyTypeKind.ZodRecord, + ...processCreateParams(second), + }); + } +} +class ZodMap extends ZodType { + get keySchema() { + return this._def.keyType; + } + get valueSchema() { + return this._def.valueType; + } + _parse(input) { + const { status, ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.map) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.map, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + const keyType = this._def.keyType; + const valueType = this._def.valueType; + const pairs = [...ctx.data.entries()].map(([key, value], index) => { + return { + key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index, "key"])), + value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index, "value"])), + }; + }); + if (ctx.common.async) { + const finalMap = new Map(); + return Promise.resolve().then(async () => { + for (const pair of pairs) { + const key = await pair.key; + const value = await pair.value; + if (key.status === "aborted" || value.status === "aborted") { + return parseUtil_INVALID; + } + if (key.status === "dirty" || value.status === "dirty") { + status.dirty(); + } + finalMap.set(key.value, value.value); + } + return { status: status.value, value: finalMap }; + }); + } + else { + const finalMap = new Map(); + for (const pair of pairs) { + const key = pair.key; + const value = pair.value; + if (key.status === "aborted" || value.status === "aborted") { + return parseUtil_INVALID; + } + if (key.status === "dirty" || value.status === "dirty") { + status.dirty(); + } + finalMap.set(key.value, value.value); + } + return { status: status.value, value: finalMap }; + } + } +} +ZodMap.create = (keyType, valueType, params) => { + return new ZodMap({ + valueType, + keyType, + typeName: ZodFirstPartyTypeKind.ZodMap, + ...processCreateParams(params), + }); +}; +class ZodSet extends ZodType { + _parse(input) { + const { status, ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.set) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.set, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + const def = this._def; + if (def.minSize !== null) { + if (ctx.data.size < def.minSize.value) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_small, + minimum: def.minSize.value, + type: "set", + inclusive: true, + exact: false, + message: def.minSize.message, + }); + status.dirty(); + } + } + if (def.maxSize !== null) { + if (ctx.data.size > def.maxSize.value) { + addIssueToContext(ctx, { + code: ZodIssueCode.too_big, + maximum: def.maxSize.value, + type: "set", + inclusive: true, + exact: false, + message: def.maxSize.message, + }); + status.dirty(); + } + } + const valueType = this._def.valueType; + function finalizeSet(elements) { + const parsedSet = new Set(); + for (const element of elements) { + if (element.status === "aborted") + return parseUtil_INVALID; + if (element.status === "dirty") + status.dirty(); + parsedSet.add(element.value); + } + return { status: status.value, value: parsedSet }; + } + const elements = [...ctx.data.values()].map((item, i) => valueType._parse(new ParseInputLazyPath(ctx, item, ctx.path, i))); + if (ctx.common.async) { + return Promise.all(elements).then((elements) => finalizeSet(elements)); + } + else { + return finalizeSet(elements); + } + } + min(minSize, message) { + return new ZodSet({ + ...this._def, + minSize: { value: minSize, message: errorUtil.toString(message) }, + }); + } + max(maxSize, message) { + return new ZodSet({ + ...this._def, + maxSize: { value: maxSize, message: errorUtil.toString(message) }, + }); + } + size(size, message) { + return this.min(size, message).max(size, message); + } + nonempty(message) { + return this.min(1, message); + } +} +ZodSet.create = (valueType, params) => { + return new ZodSet({ + valueType, + minSize: null, + maxSize: null, + typeName: ZodFirstPartyTypeKind.ZodSet, + ...processCreateParams(params), + }); +}; +class ZodFunction extends ZodType { + constructor() { + super(...arguments); + this.validate = this.implement; + } + _parse(input) { + const { ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.function) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.function, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + function makeArgsIssue(args, error) { + return makeIssue({ + data: args, + path: ctx.path, + errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), en].filter((x) => !!x), + issueData: { + code: ZodIssueCode.invalid_arguments, + argumentsError: error, + }, + }); + } + function makeReturnsIssue(returns, error) { + return makeIssue({ + data: returns, + path: ctx.path, + errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), en].filter((x) => !!x), + issueData: { + code: ZodIssueCode.invalid_return_type, + returnTypeError: error, + }, + }); + } + const params = { errorMap: ctx.common.contextualErrorMap }; + const fn = ctx.data; + if (this._def.returns instanceof ZodPromise) { + // Would love a way to avoid disabling this rule, but we need + // an alias (using an arrow function was what caused 2651). + // eslint-disable-next-line @typescript-eslint/no-this-alias + const me = this; + return OK(async function (...args) { + const error = new ZodError([]); + const parsedArgs = await me._def.args.parseAsync(args, params).catch((e) => { + error.addIssue(makeArgsIssue(args, e)); + throw error; + }); + const result = await Reflect.apply(fn, this, parsedArgs); + const parsedReturns = await me._def.returns._def.type + .parseAsync(result, params) + .catch((e) => { + error.addIssue(makeReturnsIssue(result, e)); + throw error; + }); + return parsedReturns; + }); + } + else { + // Would love a way to avoid disabling this rule, but we need + // an alias (using an arrow function was what caused 2651). + // eslint-disable-next-line @typescript-eslint/no-this-alias + const me = this; + return OK(function (...args) { + const parsedArgs = me._def.args.safeParse(args, params); + if (!parsedArgs.success) { + throw new ZodError([makeArgsIssue(args, parsedArgs.error)]); + } + const result = Reflect.apply(fn, this, parsedArgs.data); + const parsedReturns = me._def.returns.safeParse(result, params); + if (!parsedReturns.success) { + throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]); + } + return parsedReturns.data; + }); + } + } + parameters() { + return this._def.args; + } + returnType() { + return this._def.returns; + } + args(...items) { + return new ZodFunction({ + ...this._def, + args: ZodTuple.create(items).rest(ZodUnknown.create()), + }); + } + returns(returnType) { + return new ZodFunction({ + ...this._def, + returns: returnType, + }); + } + implement(func) { + const validatedFunc = this.parse(func); + return validatedFunc; + } + strictImplement(func) { + const validatedFunc = this.parse(func); + return validatedFunc; + } + static create(args, returns, params) { + return new ZodFunction({ + args: (args ? args : ZodTuple.create([]).rest(ZodUnknown.create())), + returns: returns || ZodUnknown.create(), + typeName: ZodFirstPartyTypeKind.ZodFunction, + ...processCreateParams(params), + }); + } +} +class ZodLazy extends ZodType { + get schema() { + return this._def.getter(); + } + _parse(input) { + const { ctx } = this._processInputParams(input); + const lazySchema = this._def.getter(); + return lazySchema._parse({ data: ctx.data, path: ctx.path, parent: ctx }); + } +} +ZodLazy.create = (getter, params) => { + return new ZodLazy({ + getter: getter, + typeName: ZodFirstPartyTypeKind.ZodLazy, + ...processCreateParams(params), + }); +}; +class ZodLiteral extends ZodType { + _parse(input) { + if (input.data !== this._def.value) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + received: ctx.data, + code: ZodIssueCode.invalid_literal, + expected: this._def.value, + }); + return parseUtil_INVALID; + } + return { status: "valid", value: input.data }; + } + get value() { + return this._def.value; + } +} +ZodLiteral.create = (value, params) => { + return new ZodLiteral({ + value: value, + typeName: ZodFirstPartyTypeKind.ZodLiteral, + ...processCreateParams(params), + }); +}; +function createZodEnum(values, params) { + return new ZodEnum({ + values, + typeName: ZodFirstPartyTypeKind.ZodEnum, + ...processCreateParams(params), + }); +} +class ZodEnum extends ZodType { + _parse(input) { + if (typeof input.data !== "string") { + const ctx = this._getOrReturnCtx(input); + const expectedValues = this._def.values; + addIssueToContext(ctx, { + expected: util_util.joinValues(expectedValues), + received: ctx.parsedType, + code: ZodIssueCode.invalid_type, + }); + return parseUtil_INVALID; + } + if (!this._cache) { + this._cache = new Set(this._def.values); + } + if (!this._cache.has(input.data)) { + const ctx = this._getOrReturnCtx(input); + const expectedValues = this._def.values; + addIssueToContext(ctx, { + received: ctx.data, + code: ZodIssueCode.invalid_enum_value, + options: expectedValues, + }); + return parseUtil_INVALID; + } + return OK(input.data); + } + get options() { + return this._def.values; + } + get enum() { + const enumValues = {}; + for (const val of this._def.values) { + enumValues[val] = val; + } + return enumValues; + } + get Values() { + const enumValues = {}; + for (const val of this._def.values) { + enumValues[val] = val; + } + return enumValues; + } + get Enum() { + const enumValues = {}; + for (const val of this._def.values) { + enumValues[val] = val; + } + return enumValues; + } + extract(values, newDef = this._def) { + return ZodEnum.create(values, { + ...this._def, + ...newDef, + }); + } + exclude(values, newDef = this._def) { + return ZodEnum.create(this.options.filter((opt) => !values.includes(opt)), { + ...this._def, + ...newDef, + }); + } +} +ZodEnum.create = createZodEnum; +class ZodNativeEnum extends ZodType { + _parse(input) { + const nativeEnumValues = util_util.getValidEnumValues(this._def.values); + const ctx = this._getOrReturnCtx(input); + if (ctx.parsedType !== ZodParsedType.string && ctx.parsedType !== ZodParsedType.number) { + const expectedValues = util_util.objectValues(nativeEnumValues); + addIssueToContext(ctx, { + expected: util_util.joinValues(expectedValues), + received: ctx.parsedType, + code: ZodIssueCode.invalid_type, + }); + return parseUtil_INVALID; + } + if (!this._cache) { + this._cache = new Set(util_util.getValidEnumValues(this._def.values)); + } + if (!this._cache.has(input.data)) { + const expectedValues = util_util.objectValues(nativeEnumValues); + addIssueToContext(ctx, { + received: ctx.data, + code: ZodIssueCode.invalid_enum_value, + options: expectedValues, + }); + return parseUtil_INVALID; + } + return OK(input.data); + } + get enum() { + return this._def.values; + } +} +ZodNativeEnum.create = (values, params) => { + return new ZodNativeEnum({ + values: values, + typeName: ZodFirstPartyTypeKind.ZodNativeEnum, + ...processCreateParams(params), + }); +}; +class ZodPromise extends ZodType { + unwrap() { + return this._def.type; + } + _parse(input) { + const { ctx } = this._processInputParams(input); + if (ctx.parsedType !== ZodParsedType.promise && ctx.common.async === false) { + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.promise, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + const promisified = ctx.parsedType === ZodParsedType.promise ? ctx.data : Promise.resolve(ctx.data); + return OK(promisified.then((data) => { + return this._def.type.parseAsync(data, { + path: ctx.path, + errorMap: ctx.common.contextualErrorMap, + }); + })); + } +} +ZodPromise.create = (schema, params) => { + return new ZodPromise({ + type: schema, + typeName: ZodFirstPartyTypeKind.ZodPromise, + ...processCreateParams(params), + }); +}; +class ZodEffects extends ZodType { + innerType() { + return this._def.schema; + } + sourceType() { + return this._def.schema._def.typeName === ZodFirstPartyTypeKind.ZodEffects + ? this._def.schema.sourceType() + : this._def.schema; + } + _parse(input) { + const { status, ctx } = this._processInputParams(input); + const effect = this._def.effect || null; + const checkCtx = { + addIssue: (arg) => { + addIssueToContext(ctx, arg); + if (arg.fatal) { + status.abort(); + } + else { + status.dirty(); + } + }, + get path() { + return ctx.path; + }, + }; + checkCtx.addIssue = checkCtx.addIssue.bind(checkCtx); + if (effect.type === "preprocess") { + const processed = effect.transform(ctx.data, checkCtx); + if (ctx.common.async) { + return Promise.resolve(processed).then(async (processed) => { + if (status.value === "aborted") + return parseUtil_INVALID; + const result = await this._def.schema._parseAsync({ + data: processed, + path: ctx.path, + parent: ctx, + }); + if (result.status === "aborted") + return parseUtil_INVALID; + if (result.status === "dirty") + return DIRTY(result.value); + if (status.value === "dirty") + return DIRTY(result.value); + return result; + }); + } + else { + if (status.value === "aborted") + return parseUtil_INVALID; + const result = this._def.schema._parseSync({ + data: processed, + path: ctx.path, + parent: ctx, + }); + if (result.status === "aborted") + return parseUtil_INVALID; + if (result.status === "dirty") + return DIRTY(result.value); + if (status.value === "dirty") + return DIRTY(result.value); + return result; + } + } + if (effect.type === "refinement") { + const executeRefinement = (acc) => { + const result = effect.refinement(acc, checkCtx); + if (ctx.common.async) { + return Promise.resolve(result); + } + if (result instanceof Promise) { + throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead."); + } + return acc; + }; + if (ctx.common.async === false) { + const inner = this._def.schema._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + if (inner.status === "aborted") + return parseUtil_INVALID; + if (inner.status === "dirty") + status.dirty(); + // return value is ignored + executeRefinement(inner.value); + return { status: status.value, value: inner.value }; + } + else { + return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => { + if (inner.status === "aborted") + return parseUtil_INVALID; + if (inner.status === "dirty") + status.dirty(); + return executeRefinement(inner.value).then(() => { + return { status: status.value, value: inner.value }; + }); + }); + } + } + if (effect.type === "transform") { + if (ctx.common.async === false) { + const base = this._def.schema._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + if (!isValid(base)) + return parseUtil_INVALID; + const result = effect.transform(base.value, checkCtx); + if (result instanceof Promise) { + throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`); + } + return { status: status.value, value: result }; + } + else { + return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => { + if (!isValid(base)) + return parseUtil_INVALID; + return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({ + status: status.value, + value: result, + })); + }); + } + } + util_util.assertNever(effect); + } +} +ZodEffects.create = (schema, effect, params) => { + return new ZodEffects({ + schema, + typeName: ZodFirstPartyTypeKind.ZodEffects, + effect, + ...processCreateParams(params), + }); }; -/** -* Wraps a runnable and applies partial config upon invocation. -* -* @example -* ```typescript -* import { -* type RunnableConfig, -* RunnableLambda, -* } from "@langchain/core/runnables"; -* -* const enhanceProfile = ( -* profile: Record, -* config?: RunnableConfig -* ) => { -* if (config?.configurable?.role) { -* return { ...profile, role: config.configurable.role }; -* } -* return profile; -* }; -* -* const runnable = RunnableLambda.from(enhanceProfile); -* -* // Bind configuration to the runnable to set the user's role dynamically -* const adminRunnable = runnable.withConfig({ configurable: { role: "Admin" } }); -* const userRunnable = runnable.withConfig({ configurable: { role: "User" } }); -* -* const result1 = await adminRunnable.invoke({ -* name: "Alice", -* email: "alice@example.com" -* }); -* -* // { name: "Alice", email: "alice@example.com", role: "Admin" } -* -* const result2 = await userRunnable.invoke({ -* name: "Bob", -* email: "bob@example.com" -* }); -* -* // { name: "Bob", email: "bob@example.com", role: "User" } -* ``` -*/ -var RunnableBinding = class RunnableBinding extends Runnable { - static lc_name() { - return "RunnableBinding"; - } - lc_namespace = ["langchain_core", "runnables"]; - lc_serializable = true; - bound; - config; - kwargs; - configFactories; - constructor(fields) { - super(fields); - this.bound = fields.bound; - this.kwargs = fields.kwargs; - this.config = fields.config; - this.configFactories = fields.configFactories; - } - getName(suffix) { - return this.bound.getName(suffix); - } - async _mergeConfig(...options) { - const config = mergeConfigs(this.config, ...options); - return mergeConfigs(config, ...this.configFactories ? await Promise.all(this.configFactories.map(async (configFactory) => await configFactory(config))) : []); - } - withConfig(config) { - return new this.constructor({ - bound: this.bound, - kwargs: this.kwargs, - config: { - ...this.config, - ...config - } - }); - } - withRetry(fields) { - return new RunnableRetry({ - bound: this.bound, - kwargs: this.kwargs, - config: this.config, - maxAttemptNumber: fields?.stopAfterAttempt, - ...fields - }); - } - async invoke(input, options) { - return this.bound.invoke(input, await this._mergeConfig(options, this.kwargs)); - } - async batch(inputs, options, batchOptions) { - const mergedOptions = Array.isArray(options) ? await Promise.all(options.map(async (individualOption) => this._mergeConfig(ensureConfig(individualOption), this.kwargs))) : await this._mergeConfig(ensureConfig(options), this.kwargs); - return this.bound.batch(inputs, mergedOptions, batchOptions); - } - /** @internal */ - _concatOutputChunks(first, second) { - return this.bound._concatOutputChunks(first, second); - } - async *_streamIterator(input, options) { - yield* this.bound._streamIterator(input, await this._mergeConfig(ensureConfig(options), this.kwargs)); - } - async stream(input, options) { - return this.bound.stream(input, await this._mergeConfig(ensureConfig(options), this.kwargs)); - } - async *transform(generator, options) { - yield* this.bound.transform(generator, await this._mergeConfig(ensureConfig(options), this.kwargs)); - } - streamEvents(input, options, streamOptions) { - const outerThis = this; - const generator = async function* () { - yield* outerThis.bound.streamEvents(input, { - ...await outerThis._mergeConfig(ensureConfig(options), outerThis.kwargs), - version: options.version - }, streamOptions); - }; - return IterableReadableStream.fromAsyncGenerator(generator()); - } - static isRunnableBinding(thing) { - return thing.bound && Runnable.isRunnable(thing.bound); - } - /** - * Bind lifecycle listeners to a Runnable, returning a new Runnable. - * The Run object contains information about the run, including its id, - * type, input, output, error, startTime, endTime, and any tags or metadata - * added to the run. - * - * @param {Object} params - The object containing the callback functions. - * @param {(run: Run) => void} params.onStart - Called before the runnable starts running, with the Run object. - * @param {(run: Run) => void} params.onEnd - Called after the runnable finishes running, with the Run object. - * @param {(run: Run) => void} params.onError - Called if the runnable throws an error, with the Run object. - */ - withListeners({ onStart, onEnd, onError }) { - return new RunnableBinding({ - bound: this.bound, - kwargs: this.kwargs, - config: this.config, - configFactories: [(config) => ({ callbacks: [new RootListenersTracer({ - config, - onStart, - onEnd, - onError - })] })] - }); - } +ZodEffects.createWithPreprocess = (preprocess, schema, params) => { + return new ZodEffects({ + schema, + effect: { type: "preprocess", transform: preprocess }, + typeName: ZodFirstPartyTypeKind.ZodEffects, + ...processCreateParams(params), + }); }; -/** -* A runnable that delegates calls to another runnable -* with each element of the input sequence. -* @example -* ```typescript -* import { RunnableEach, RunnableLambda } from "@langchain/core/runnables"; -* -* const toUpperCase = (input: string): string => input.toUpperCase(); -* const addGreeting = (input: string): string => `Hello, ${input}!`; -* -* const upperCaseLambda = RunnableLambda.from(toUpperCase); -* const greetingLambda = RunnableLambda.from(addGreeting); -* -* const chain = new RunnableEach({ -* bound: upperCaseLambda.pipe(greetingLambda), -* }); -* -* const result = await chain.invoke(["alice", "bob", "carol"]) -* -* // ["Hello, ALICE!", "Hello, BOB!", "Hello, CAROL!"] -* ``` -*/ -var RunnableEach = class RunnableEach extends Runnable { - static lc_name() { - return "RunnableEach"; - } - lc_serializable = true; - lc_namespace = ["langchain_core", "runnables"]; - bound; - constructor(fields) { - super(fields); - this.bound = fields.bound; - } - /** - * Invokes the runnable with the specified input and configuration. - * @param input The input to invoke the runnable with. - * @param config The configuration to invoke the runnable with. - * @returns A promise that resolves to the output of the runnable. - */ - async invoke(inputs, config) { - return this._callWithConfig(this._invoke.bind(this), inputs, config); - } - /** - * A helper method that is used to invoke the runnable with the specified input and configuration. - * @param input The input to invoke the runnable with. - * @param config The configuration to invoke the runnable with. - * @returns A promise that resolves to the output of the runnable. - */ - async _invoke(inputs, config, runManager) { - return this.bound.batch(inputs, config_patchConfig(config, { callbacks: runManager?.getChild() })); - } - /** - * Bind lifecycle listeners to a Runnable, returning a new Runnable. - * The Run object contains information about the run, including its id, - * type, input, output, error, startTime, endTime, and any tags or metadata - * added to the run. - * - * @param {Object} params - The object containing the callback functions. - * @param {(run: Run) => void} params.onStart - Called before the runnable starts running, with the Run object. - * @param {(run: Run) => void} params.onEnd - Called after the runnable finishes running, with the Run object. - * @param {(run: Run) => void} params.onError - Called if the runnable throws an error, with the Run object. - */ - withListeners({ onStart, onEnd, onError }) { - return new RunnableEach({ bound: this.bound.withListeners({ - onStart, - onEnd, - onError - }) }); - } + +class ZodOptional extends ZodType { + _parse(input) { + const parsedType = this._getType(input); + if (parsedType === ZodParsedType.undefined) { + return OK(undefined); + } + return this._def.innerType._parse(input); + } + unwrap() { + return this._def.innerType; + } +} +ZodOptional.create = (type, params) => { + return new ZodOptional({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodOptional, + ...processCreateParams(params), + }); }; -/** -* Base class for runnables that can be retried a -* specified number of times. -* @example -* ```typescript -* import { -* RunnableLambda, -* RunnableRetry, -* } from "@langchain/core/runnables"; -* -* // Simulate an API call that fails -* const simulateApiCall = (input: string): string => { -* console.log(`Attempting API call with input: ${input}`); -* throw new Error("API call failed due to network issue"); -* }; -* -* const apiCallLambda = RunnableLambda.from(simulateApiCall); -* -* // Apply retry logic using the .withRetry() method -* const apiCallWithRetry = apiCallLambda.withRetry({ stopAfterAttempt: 3 }); -* -* // Alternatively, create a RunnableRetry instance manually -* const manualRetry = new RunnableRetry({ -* bound: apiCallLambda, -* maxAttemptNumber: 3, -* config: {}, -* }); -* -* // Example invocation using the .withRetry() method -* const res = await apiCallWithRetry -* .invoke("Request 1") -* .catch((error) => { -* console.error("Failed after multiple retries:", error.message); -* }); -* -* // Example invocation using the manual retry instance -* const res2 = await manualRetry -* .invoke("Request 2") -* .catch((error) => { -* console.error("Failed after multiple retries:", error.message); -* }); -* ``` -*/ -var RunnableRetry = class extends RunnableBinding { - static lc_name() { - return "RunnableRetry"; - } - lc_namespace = ["langchain_core", "runnables"]; - maxAttemptNumber = 3; - onFailedAttempt = () => {}; - constructor(fields) { - super(fields); - this.maxAttemptNumber = fields.maxAttemptNumber ?? this.maxAttemptNumber; - this.onFailedAttempt = fields.onFailedAttempt ?? this.onFailedAttempt; - } - _patchConfigForRetry(attempt, config, runManager) { - const tag = attempt > 1 ? `retry:attempt:${attempt}` : void 0; - return config_patchConfig(config, { callbacks: runManager?.getChild(tag) }); - } - async _invoke(input, config, runManager) { - return p_retry_pRetry((attemptNumber) => super.invoke(input, this._patchConfigForRetry(attemptNumber, config, runManager)), { - onFailedAttempt: ({ error }) => this.onFailedAttempt(error, input), - retries: Math.max(this.maxAttemptNumber - 1, 0), - randomize: true - }); - } - /** - * Method that invokes the runnable with the specified input, run manager, - * and config. It handles the retry logic by catching any errors and - * recursively invoking itself with the updated config for the next retry - * attempt. - * @param input The input for the runnable. - * @param runManager The run manager for the runnable. - * @param config The config for the runnable. - * @returns A promise that resolves to the output of the runnable. - */ - async invoke(input, config) { - return this._callWithConfig(this._invoke.bind(this), input, config); - } - async _batch(inputs, configs, runManagers, batchOptions) { - const resultsMap = {}; - try { - await p_retry_pRetry(async (attemptNumber) => { - const remainingIndexes = inputs.map((_, i) => i).filter((i) => resultsMap[i.toString()] === void 0 || resultsMap[i.toString()] instanceof Error); - const remainingInputs = remainingIndexes.map((i) => inputs[i]); - const patchedConfigs = remainingIndexes.map((i) => this._patchConfigForRetry(attemptNumber, configs?.[i], runManagers?.[i])); - const results = await super.batch(remainingInputs, patchedConfigs, { - ...batchOptions, - returnExceptions: true - }); - let firstException; - for (let i = 0; i < results.length; i += 1) { - const result = results[i]; - const resultMapIndex = remainingIndexes[i]; - if (result instanceof Error) { - if (firstException === void 0) { - firstException = result; - firstException.input = remainingInputs[i]; - } - } - resultsMap[resultMapIndex.toString()] = result; - } - if (firstException) throw firstException; - return results; - }, { - onFailedAttempt: ({ error }) => this.onFailedAttempt(error, error.input), - retries: Math.max(this.maxAttemptNumber - 1, 0), - randomize: true - }); - } catch (e) { - if (batchOptions?.returnExceptions !== true) throw e; - } - return Object.keys(resultsMap).sort((a, b) => parseInt(a, 10) - parseInt(b, 10)).map((key) => resultsMap[parseInt(key, 10)]); - } - async batch(inputs, options, batchOptions) { - return this._batchWithConfig(this._batch.bind(this), inputs, options, batchOptions); - } +class ZodNullable extends ZodType { + _parse(input) { + const parsedType = this._getType(input); + if (parsedType === ZodParsedType.null) { + return OK(null); + } + return this._def.innerType._parse(input); + } + unwrap() { + return this._def.innerType; + } +} +ZodNullable.create = (type, params) => { + return new ZodNullable({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodNullable, + ...processCreateParams(params), + }); +}; +class ZodDefault extends ZodType { + _parse(input) { + const { ctx } = this._processInputParams(input); + let data = ctx.data; + if (ctx.parsedType === ZodParsedType.undefined) { + data = this._def.defaultValue(); + } + return this._def.innerType._parse({ + data, + path: ctx.path, + parent: ctx, + }); + } + removeDefault() { + return this._def.innerType; + } +} +ZodDefault.create = (type, params) => { + return new ZodDefault({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodDefault, + defaultValue: typeof params.default === "function" ? params.default : () => params.default, + ...processCreateParams(params), + }); +}; +class ZodCatch extends ZodType { + _parse(input) { + const { ctx } = this._processInputParams(input); + // newCtx is used to not collect issues from inner types in ctx + const newCtx = { + ...ctx, + common: { + ...ctx.common, + issues: [], + }, + }; + const result = this._def.innerType._parse({ + data: newCtx.data, + path: newCtx.path, + parent: { + ...newCtx, + }, + }); + if (isAsync(result)) { + return result.then((result) => { + return { + status: "valid", + value: result.status === "valid" + ? result.value + : this._def.catchValue({ + get error() { + return new ZodError(newCtx.common.issues); + }, + input: newCtx.data, + }), + }; + }); + } + else { + return { + status: "valid", + value: result.status === "valid" + ? result.value + : this._def.catchValue({ + get error() { + return new ZodError(newCtx.common.issues); + }, + input: newCtx.data, + }), + }; + } + } + removeCatch() { + return this._def.innerType; + } +} +ZodCatch.create = (type, params) => { + return new ZodCatch({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodCatch, + catchValue: typeof params.catch === "function" ? params.catch : () => params.catch, + ...processCreateParams(params), + }); }; -/** -* A sequence of runnables, where the output of each is the input of the next. -* @example -* ```typescript -* const promptTemplate = PromptTemplate.fromTemplate( -* "Tell me a joke about {topic}", -* ); -* const chain = RunnableSequence.from([promptTemplate, new ChatOpenAI({ model: "gpt-4o-mini" })]); -* const result = await chain.invoke({ topic: "bears" }); -* ``` -*/ -var RunnableSequence = class RunnableSequence extends Runnable { - static lc_name() { - return "RunnableSequence"; - } - first; - middle = []; - last; - omitSequenceTags = false; - lc_serializable = true; - lc_namespace = ["langchain_core", "runnables"]; - constructor(fields) { - super(fields); - this.first = fields.first; - this.middle = fields.middle ?? this.middle; - this.last = fields.last; - this.name = fields.name; - this.omitSequenceTags = fields.omitSequenceTags ?? this.omitSequenceTags; - } - get steps() { - return [ - this.first, - ...this.middle, - this.last - ]; - } - async invoke(input, options) { - const config = ensureConfig(options); - const callbackManager_ = await getCallbackManagerForConfig(config); - const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), config.runId, void 0, void 0, void 0, config?.runName); - delete config.runId; - let nextStepInput = input; - let finalOutput; - try { - const initialSteps = [this.first, ...this.middle]; - for (let i = 0; i < initialSteps.length; i += 1) { - const step = initialSteps[i]; - const promise = step.invoke(nextStepInput, config_patchConfig(config, { callbacks: runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:${i + 1}`) })); - nextStepInput = await raceWithSignal(promise, options?.signal); - } - if (options?.signal?.aborted) throw getAbortSignalError(options.signal); - finalOutput = await this.last.invoke(nextStepInput, config_patchConfig(config, { callbacks: runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:${this.steps.length}`) })); - } catch (e) { - await runManager?.handleChainError(e); - throw e; - } - await runManager?.handleChainEnd(base_coerceToDict(finalOutput, "output")); - return finalOutput; - } - async batch(inputs, options, batchOptions) { - const configList = this._getOptionsList(options ?? {}, inputs.length); - const callbackManagers = await Promise.all(configList.map(getCallbackManagerForConfig)); - const runManagers = await Promise.all(callbackManagers.map(async (callbackManager, i) => { - const handleStartRes = await callbackManager?.handleChainStart(this.toJSON(), base_coerceToDict(inputs[i], "input"), configList[i].runId, void 0, void 0, void 0, configList[i].runName); - delete configList[i].runId; - return handleStartRes; - })); - let nextStepInputs = inputs; - try { - for (let i = 0; i < this.steps.length; i += 1) { - const step = this.steps[i]; - const promise = step.batch(nextStepInputs, runManagers.map((runManager, j) => { - const childRunManager = runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:${i + 1}`); - return config_patchConfig(configList[j], { callbacks: childRunManager }); - }), batchOptions); - nextStepInputs = await raceWithSignal(promise, configList[0]?.signal); - } - } catch (e) { - await Promise.all(runManagers.map((runManager) => runManager?.handleChainError(e))); - throw e; - } - await Promise.all(runManagers.map((runManager) => runManager?.handleChainEnd(base_coerceToDict(nextStepInputs, "output")))); - return nextStepInputs; - } - /** @internal */ - _concatOutputChunks(first, second) { - return this.last._concatOutputChunks(first, second); - } - async *_streamIterator(input, options) { - const callbackManager_ = await getCallbackManagerForConfig(options); - const { runId,...otherOptions } = options ?? {}; - const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), runId, void 0, void 0, void 0, otherOptions?.runName); - const steps = [ - this.first, - ...this.middle, - this.last - ]; - let concatSupported = true; - let finalOutput; - async function* inputGenerator() { - yield input; - } - try { - let finalGenerator = steps[0].transform(inputGenerator(), config_patchConfig(otherOptions, { callbacks: runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:1`) })); - for (let i = 1; i < steps.length; i += 1) { - const step = steps[i]; - finalGenerator = await step.transform(finalGenerator, config_patchConfig(otherOptions, { callbacks: runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:${i + 1}`) })); - } - for await (const chunk of finalGenerator) { - options?.signal?.throwIfAborted(); - yield chunk; - if (concatSupported) if (finalOutput === void 0) finalOutput = chunk; - else try { - finalOutput = this._concatOutputChunks(finalOutput, chunk); - } catch { - finalOutput = void 0; - concatSupported = false; - } - } - } catch (e) { - await runManager?.handleChainError(e); - throw e; - } - await runManager?.handleChainEnd(base_coerceToDict(finalOutput, "output")); - } - getGraph(config) { - const graph = new Graph(); - let currentLastNode = null; - this.steps.forEach((step, index) => { - const stepGraph = step.getGraph(config); - if (index !== 0) stepGraph.trimFirstNode(); - if (index !== this.steps.length - 1) stepGraph.trimLastNode(); - graph.extend(stepGraph); - const stepFirstNode = stepGraph.firstNode(); - if (!stepFirstNode) throw new Error(`Runnable ${step} has no first node`); - if (currentLastNode) graph.addEdge(currentLastNode, stepFirstNode); - currentLastNode = stepGraph.lastNode(); - }); - return graph; - } - pipe(coerceable) { - if (RunnableSequence.isRunnableSequence(coerceable)) return new RunnableSequence({ - first: this.first, - middle: this.middle.concat([ - this.last, - coerceable.first, - ...coerceable.middle - ]), - last: coerceable.last, - name: this.name ?? coerceable.name - }); - else return new RunnableSequence({ - first: this.first, - middle: [...this.middle, this.last], - last: _coerceToRunnable(coerceable), - name: this.name - }); - } - static isRunnableSequence(thing) { - return Array.isArray(thing.middle) && Runnable.isRunnable(thing); - } - static from([first, ...runnables], nameOrFields) { - let extra = {}; - if (typeof nameOrFields === "string") extra.name = nameOrFields; - else if (nameOrFields !== void 0) extra = nameOrFields; - return new RunnableSequence({ - ...extra, - first: _coerceToRunnable(first), - middle: runnables.slice(0, -1).map(_coerceToRunnable), - last: _coerceToRunnable(runnables[runnables.length - 1]) - }); - } +class ZodNaN extends ZodType { + _parse(input) { + const parsedType = this._getType(input); + if (parsedType !== ZodParsedType.nan) { + const ctx = this._getOrReturnCtx(input); + addIssueToContext(ctx, { + code: ZodIssueCode.invalid_type, + expected: ZodParsedType.nan, + received: ctx.parsedType, + }); + return parseUtil_INVALID; + } + return { status: "valid", value: input.data }; + } +} +ZodNaN.create = (params) => { + return new ZodNaN({ + typeName: ZodFirstPartyTypeKind.ZodNaN, + ...processCreateParams(params), + }); +}; +const BRAND = Symbol("zod_brand"); +class ZodBranded extends ZodType { + _parse(input) { + const { ctx } = this._processInputParams(input); + const data = ctx.data; + return this._def.type._parse({ + data, + path: ctx.path, + parent: ctx, + }); + } + unwrap() { + return this._def.type; + } +} +class ZodPipeline extends ZodType { + _parse(input) { + const { status, ctx } = this._processInputParams(input); + if (ctx.common.async) { + const handleAsync = async () => { + const inResult = await this._def.in._parseAsync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + if (inResult.status === "aborted") + return parseUtil_INVALID; + if (inResult.status === "dirty") { + status.dirty(); + return DIRTY(inResult.value); + } + else { + return this._def.out._parseAsync({ + data: inResult.value, + path: ctx.path, + parent: ctx, + }); + } + }; + return handleAsync(); + } + else { + const inResult = this._def.in._parseSync({ + data: ctx.data, + path: ctx.path, + parent: ctx, + }); + if (inResult.status === "aborted") + return parseUtil_INVALID; + if (inResult.status === "dirty") { + status.dirty(); + return { + status: "dirty", + value: inResult.value, + }; + } + else { + return this._def.out._parseSync({ + data: inResult.value, + path: ctx.path, + parent: ctx, + }); + } + } + } + static create(a, b) { + return new ZodPipeline({ + in: a, + out: b, + typeName: ZodFirstPartyTypeKind.ZodPipeline, + }); + } +} +class ZodReadonly extends ZodType { + _parse(input) { + const result = this._def.innerType._parse(input); + const freeze = (data) => { + if (isValid(data)) { + data.value = Object.freeze(data.value); + } + return data; + }; + return isAsync(result) ? result.then((data) => freeze(data)) : freeze(result); + } + unwrap() { + return this._def.innerType; + } +} +ZodReadonly.create = (type, params) => { + return new ZodReadonly({ + innerType: type, + typeName: ZodFirstPartyTypeKind.ZodReadonly, + ...processCreateParams(params), + }); }; +//////////////////////////////////////// +//////////////////////////////////////// +////////// ////////// +////////// z.custom ////////// +////////// ////////// +//////////////////////////////////////// +//////////////////////////////////////// +function cleanParams(params, data) { + const p = typeof params === "function" ? params(data) : typeof params === "string" ? { message: params } : params; + const p2 = typeof p === "string" ? { message: p } : p; + return p2; +} +function custom(check, _params = {}, /** -* A runnable that runs a mapping of runnables in parallel, -* and returns a mapping of their outputs. -* @example -* ```typescript -* const mapChain = RunnableMap.from({ -* joke: PromptTemplate.fromTemplate("Tell me a joke about {topic}").pipe( -* new ChatAnthropic({}), -* ), -* poem: PromptTemplate.fromTemplate("write a 2-line poem about {topic}").pipe( -* new ChatAnthropic({}), -* ), -* }); -* const result = await mapChain.invoke({ topic: "bear" }); -* ``` -*/ -var RunnableMap = class RunnableMap extends Runnable { - static lc_name() { - return "RunnableMap"; - } - lc_namespace = ["langchain_core", "runnables"]; - lc_serializable = true; - steps; - getStepsKeys() { - return Object.keys(this.steps); - } - constructor(fields) { - super(fields); - this.steps = {}; - for (const [key, value] of Object.entries(fields.steps)) this.steps[key] = _coerceToRunnable(value); - } - static from(steps) { - return new RunnableMap({ steps }); - } - async invoke(input, options) { - const config = ensureConfig(options); - const callbackManager_ = await getCallbackManagerForConfig(config); - const runManager = await callbackManager_?.handleChainStart(this.toJSON(), { input }, config.runId, void 0, void 0, void 0, config?.runName); - delete config.runId; - const output = {}; - try { - const promises = Object.entries(this.steps).map(async ([key, runnable]) => { - output[key] = await runnable.invoke(input, config_patchConfig(config, { callbacks: runManager?.getChild(`map:key:${key}`) })); - }); - await raceWithSignal(Promise.all(promises), options?.signal); - } catch (e) { - await runManager?.handleChainError(e); - throw e; - } - await runManager?.handleChainEnd(output); - return output; - } - async *_transform(generator, runManager, options) { - const steps = { ...this.steps }; - const inputCopies = atee(generator, Object.keys(steps).length); - const tasks = new Map(Object.entries(steps).map(([key, runnable], i) => { - const gen = runnable.transform(inputCopies[i], config_patchConfig(options, { callbacks: runManager?.getChild(`map:key:${key}`) })); - return [key, gen.next().then((result) => ({ - key, - gen, - result - }))]; - })); - while (tasks.size) { - const promise = Promise.race(tasks.values()); - const { key, result, gen } = await raceWithSignal(promise, options?.signal); - tasks.delete(key); - if (!result.done) { - yield { [key]: result.value }; - tasks.set(key, gen.next().then((result$1) => ({ - key, - gen, - result: result$1 - }))); - } - } - } - transform(generator, options) { - return this._transformStreamWithConfig(generator, this._transform.bind(this), options); - } - async stream(input, options) { - async function* generator() { - yield input; - } - const config = ensureConfig(options); - const wrappedGenerator = new AsyncGeneratorWithSetup({ - generator: this.transform(generator(), config), - config - }); - await wrappedGenerator.setup; - return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); - } + * @deprecated + * + * Pass `fatal` into the params object instead: + * + * ```ts + * z.string().custom((val) => val.length > 5, { fatal: false }) + * ``` + * + */ +fatal) { + if (check) + return ZodAny.create().superRefine((data, ctx) => { + const r = check(data); + if (r instanceof Promise) { + return r.then((r) => { + if (!r) { + const params = cleanParams(_params, data); + const _fatal = params.fatal ?? fatal ?? true; + ctx.addIssue({ code: "custom", ...params, fatal: _fatal }); + } + }); + } + if (!r) { + const params = cleanParams(_params, data); + const _fatal = params.fatal ?? fatal ?? true; + ctx.addIssue({ code: "custom", ...params, fatal: _fatal }); + } + return; + }); + return ZodAny.create(); +} + +const late = { + object: ZodObject.lazycreate, +}; +var ZodFirstPartyTypeKind; +(function (ZodFirstPartyTypeKind) { + ZodFirstPartyTypeKind["ZodString"] = "ZodString"; + ZodFirstPartyTypeKind["ZodNumber"] = "ZodNumber"; + ZodFirstPartyTypeKind["ZodNaN"] = "ZodNaN"; + ZodFirstPartyTypeKind["ZodBigInt"] = "ZodBigInt"; + ZodFirstPartyTypeKind["ZodBoolean"] = "ZodBoolean"; + ZodFirstPartyTypeKind["ZodDate"] = "ZodDate"; + ZodFirstPartyTypeKind["ZodSymbol"] = "ZodSymbol"; + ZodFirstPartyTypeKind["ZodUndefined"] = "ZodUndefined"; + ZodFirstPartyTypeKind["ZodNull"] = "ZodNull"; + ZodFirstPartyTypeKind["ZodAny"] = "ZodAny"; + ZodFirstPartyTypeKind["ZodUnknown"] = "ZodUnknown"; + ZodFirstPartyTypeKind["ZodNever"] = "ZodNever"; + ZodFirstPartyTypeKind["ZodVoid"] = "ZodVoid"; + ZodFirstPartyTypeKind["ZodArray"] = "ZodArray"; + ZodFirstPartyTypeKind["ZodObject"] = "ZodObject"; + ZodFirstPartyTypeKind["ZodUnion"] = "ZodUnion"; + ZodFirstPartyTypeKind["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion"; + ZodFirstPartyTypeKind["ZodIntersection"] = "ZodIntersection"; + ZodFirstPartyTypeKind["ZodTuple"] = "ZodTuple"; + ZodFirstPartyTypeKind["ZodRecord"] = "ZodRecord"; + ZodFirstPartyTypeKind["ZodMap"] = "ZodMap"; + ZodFirstPartyTypeKind["ZodSet"] = "ZodSet"; + ZodFirstPartyTypeKind["ZodFunction"] = "ZodFunction"; + ZodFirstPartyTypeKind["ZodLazy"] = "ZodLazy"; + ZodFirstPartyTypeKind["ZodLiteral"] = "ZodLiteral"; + ZodFirstPartyTypeKind["ZodEnum"] = "ZodEnum"; + ZodFirstPartyTypeKind["ZodEffects"] = "ZodEffects"; + ZodFirstPartyTypeKind["ZodNativeEnum"] = "ZodNativeEnum"; + ZodFirstPartyTypeKind["ZodOptional"] = "ZodOptional"; + ZodFirstPartyTypeKind["ZodNullable"] = "ZodNullable"; + ZodFirstPartyTypeKind["ZodDefault"] = "ZodDefault"; + ZodFirstPartyTypeKind["ZodCatch"] = "ZodCatch"; + ZodFirstPartyTypeKind["ZodPromise"] = "ZodPromise"; + ZodFirstPartyTypeKind["ZodBranded"] = "ZodBranded"; + ZodFirstPartyTypeKind["ZodPipeline"] = "ZodPipeline"; + ZodFirstPartyTypeKind["ZodReadonly"] = "ZodReadonly"; +})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {})); +// requires TS 4.4+ +class types_Class { + constructor(..._) { } +} +const instanceOfType = ( +// const instanceOfType = any>( +cls, params = { + message: `Input not instance of ${cls.name}`, +}) => custom((data) => data instanceof cls, params); +const stringType = ZodString.create; +const numberType = ZodNumber.create; +const nanType = ZodNaN.create; +const bigIntType = ZodBigInt.create; +const booleanType = ZodBoolean.create; +const dateType = ZodDate.create; +const symbolType = ZodSymbol.create; +const undefinedType = ZodUndefined.create; +const nullType = ZodNull.create; +const anyType = ZodAny.create; +const unknownType = ZodUnknown.create; +const neverType = ZodNever.create; +const voidType = ZodVoid.create; +const arrayType = ZodArray.create; +const objectType = ZodObject.create; +const strictObjectType = ZodObject.strictCreate; +const unionType = ZodUnion.create; +const discriminatedUnionType = ZodDiscriminatedUnion.create; +const intersectionType = ZodIntersection.create; +const tupleType = ZodTuple.create; +const recordType = ZodRecord.create; +const mapType = ZodMap.create; +const setType = ZodSet.create; +const functionType = ZodFunction.create; +const lazyType = ZodLazy.create; +const literalType = ZodLiteral.create; +const enumType = ZodEnum.create; +const nativeEnumType = ZodNativeEnum.create; +const promiseType = ZodPromise.create; +const effectsType = ZodEffects.create; +const optionalType = ZodOptional.create; +const nullableType = ZodNullable.create; +const preprocessType = ZodEffects.createWithPreprocess; +const pipelineType = ZodPipeline.create; +const ostring = () => stringType().optional(); +const onumber = () => numberType().optional(); +const oboolean = () => booleanType().optional(); +const coerce = { + string: ((arg) => ZodString.create({ ...arg, coerce: true })), + number: ((arg) => ZodNumber.create({ ...arg, coerce: true })), + boolean: ((arg) => ZodBoolean.create({ + ...arg, + coerce: true, + })), + bigint: ((arg) => ZodBigInt.create({ ...arg, coerce: true })), + date: ((arg) => ZodDate.create({ ...arg, coerce: true })), }; -/** -* A runnable that wraps a traced LangSmith function. -*/ -var RunnableTraceable = class RunnableTraceable extends Runnable { - lc_serializable = false; - lc_namespace = ["langchain_core", "runnables"]; - func; - constructor(fields) { - super(fields); - if (!isTraceableFunction(fields.func)) throw new Error("RunnableTraceable requires a function that is wrapped in traceable higher-order function"); - this.func = fields.func; - } - async invoke(input, options) { - const [config] = this._getOptionsList(options ?? {}, 1); - const callbacks = await getCallbackManagerForConfig(config); - const promise = this.func(config_patchConfig(config, { callbacks }), input); - return raceWithSignal(promise, config?.signal); + +const types_NEVER = (/* unused pure expression or super */ null && (INVALID)); + +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/array.js + + + + +//#region src/utils/zod-to-json-schema/parsers/array.ts +function parseArrayDef(def, refs) { + const res = { type: "array" }; + if (def.type?._def && def.type?._def?.typeName !== ZodFirstPartyTypeKind.ZodAny) res.items = parseDef(def.type._def, { + ...refs, + currentPath: [...refs.currentPath, "items"] + }); + if (def.minLength) setResponseValueAndErrors(res, "minItems", def.minLength.value, def.minLength.message, refs); + if (def.maxLength) setResponseValueAndErrors(res, "maxItems", def.maxLength.value, def.maxLength.message, refs); + if (def.exactLength) { + setResponseValueAndErrors(res, "minItems", def.exactLength.value, def.exactLength.message, refs); + setResponseValueAndErrors(res, "maxItems", def.exactLength.value, def.exactLength.message, refs); } - async *_streamIterator(input, options) { - const [config] = this._getOptionsList(options ?? {}, 1); - const result = await this.invoke(input, options); - if (isAsyncIterable(result)) { - for await (const item of result) { - config?.signal?.throwIfAborted(); - yield item; + return res; +} + +//#endregion + +//# sourceMappingURL=array.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/bigint.js + + +//#region src/utils/zod-to-json-schema/parsers/bigint.ts +function parseBigintDef(def, refs) { + const res = { + type: "integer", + format: "int64" + }; + if (!def.checks) return res; + for (const check of def.checks) switch (check.kind) { + case "min": + if (refs.target === "jsonSchema7") if (check.inclusive) setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); + else setResponseValueAndErrors(res, "exclusiveMinimum", check.value, check.message, refs); + else { + if (!check.inclusive) res.exclusiveMinimum = true; + setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); } - return; - } - if (isIterator(result)) { - while (true) { - config?.signal?.throwIfAborted(); - const state = result.next(); - if (state.done) break; - yield state.value; + break; + case "max": + if (refs.target === "jsonSchema7") if (check.inclusive) setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); + else setResponseValueAndErrors(res, "exclusiveMaximum", check.value, check.message, refs); + else { + if (!check.inclusive) res.exclusiveMaximum = true; + setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); } - return; - } - yield result; - } - static from(func) { - return new RunnableTraceable({ func }); + break; + case "multipleOf": + setResponseValueAndErrors(res, "multipleOf", check.value, check.message, refs); + break; } -}; -function assertNonTraceableFunction(func) { - if (isTraceableFunction(func)) throw new Error("RunnableLambda requires a function that is not wrapped in traceable higher-order function. This shouldn't happen."); + return res; } -/** -* A runnable that wraps an arbitrary function that takes a single argument. -* @example -* ```typescript -* import { RunnableLambda } from "@langchain/core/runnables"; -* -* const add = (input: { x: number; y: number }) => input.x + input.y; -* -* const multiply = (input: { value: number; multiplier: number }) => -* input.value * input.multiplier; -* -* // Create runnables for the functions -* const addLambda = RunnableLambda.from(add); -* const multiplyLambda = RunnableLambda.from(multiply); -* -* // Chain the lambdas for a mathematical operation -* const chainedLambda = addLambda.pipe((result) => -* multiplyLambda.invoke({ value: result, multiplier: 2 }) -* ); -* -* // Example invocation of the chainedLambda -* const result = await chainedLambda.invoke({ x: 2, y: 3 }); -* -* // Will log "10" (since (2 + 3) * 2 = 10) -* ``` -*/ -var RunnableLambda = class RunnableLambda extends Runnable { - static lc_name() { - return "RunnableLambda"; - } - lc_namespace = ["langchain_core", "runnables"]; - func; - constructor(fields) { - if (isTraceableFunction(fields.func)) return RunnableTraceable.from(fields.func); - super(fields); - assertNonTraceableFunction(fields.func); - this.func = fields.func; - } - static from(func) { - return new RunnableLambda({ func }); - } - async _invoke(input, config, runManager) { - return new Promise((resolve, reject) => { - const childConfig = config_patchConfig(config, { - callbacks: runManager?.getChild(), - recursionLimit: (config?.recursionLimit ?? DEFAULT_RECURSION_LIMIT) - 1 - }); - async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(childConfig), async () => { - try { - let output = await this.func(input, { ...childConfig }); - if (output && Runnable.isRunnable(output)) { - if (config?.recursionLimit === 0) throw new Error("Recursion limit reached."); - output = await output.invoke(input, { - ...childConfig, - recursionLimit: (childConfig.recursionLimit ?? DEFAULT_RECURSION_LIMIT) - 1 - }); - } else if (isAsyncIterable(output)) { - let finalOutput; - for await (const chunk of consumeAsyncIterableInContext(childConfig, output)) { - config?.signal?.throwIfAborted(); - if (finalOutput === void 0) finalOutput = chunk; - else try { - finalOutput = this._concatOutputChunks(finalOutput, chunk); - } catch { - finalOutput = chunk; - } - } - output = finalOutput; - } else if (isIterableIterator(output)) { - let finalOutput; - for (const chunk of consumeIteratorInContext(childConfig, output)) { - config?.signal?.throwIfAborted(); - if (finalOutput === void 0) finalOutput = chunk; - else try { - finalOutput = this._concatOutputChunks(finalOutput, chunk); - } catch { - finalOutput = chunk; - } - } - output = finalOutput; - } - resolve(output); - } catch (e) { - reject(e); - } - }); - }); - } - async invoke(input, options) { - return this._callWithConfig(this._invoke.bind(this), input, options); - } - async *_transform(generator, runManager, config) { - let finalChunk; - for await (const chunk of generator) if (finalChunk === void 0) finalChunk = chunk; - else try { - finalChunk = this._concatOutputChunks(finalChunk, chunk); - } catch { - finalChunk = chunk; - } - const childConfig = config_patchConfig(config, { - callbacks: runManager?.getChild(), - recursionLimit: (config?.recursionLimit ?? DEFAULT_RECURSION_LIMIT) - 1 - }); - const output = await new Promise((resolve, reject) => { - async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(childConfig), async () => { - try { - const res = await this.func(finalChunk, { - ...childConfig, - config: childConfig - }); - resolve(res); - } catch (e) { - reject(e); - } - }); - }); - if (output && Runnable.isRunnable(output)) { - if (config?.recursionLimit === 0) throw new Error("Recursion limit reached."); - const stream = await output.stream(finalChunk, childConfig); - for await (const chunk of stream) yield chunk; - } else if (isAsyncIterable(output)) for await (const chunk of consumeAsyncIterableInContext(childConfig, output)) { - config?.signal?.throwIfAborted(); - yield chunk; - } - else if (isIterableIterator(output)) for (const chunk of consumeIteratorInContext(childConfig, output)) { - config?.signal?.throwIfAborted(); - yield chunk; - } - else yield output; - } - transform(generator, options) { - return this._transformStreamWithConfig(generator, this._transform.bind(this), options); - } - async stream(input, options) { - async function* generator() { - yield input; - } - const config = ensureConfig(options); - const wrappedGenerator = new AsyncGeneratorWithSetup({ - generator: this.transform(generator(), config), - config - }); - await wrappedGenerator.setup; - return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); - } + +//#endregion + +//# sourceMappingURL=bigint.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/boolean.js +//#region src/utils/zod-to-json-schema/parsers/boolean.ts +function parseBooleanDef() { + return { type: "boolean" }; +} + +//#endregion + +//# sourceMappingURL=boolean.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/branded.js + + +//#region src/utils/zod-to-json-schema/parsers/branded.ts +function parseBrandedDef(_def, refs) { + return parseDef(_def.type._def, refs); +} + +//#endregion + +//# sourceMappingURL=branded.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/catch.js + + +//#region src/utils/zod-to-json-schema/parsers/catch.ts +const parseCatchDef = (def, refs) => { + return parseDef(def.innerType._def, refs); }; -/** -* A runnable that runs a mapping of runnables in parallel, -* and returns a mapping of their outputs. -* @example -* ```typescript -* import { -* RunnableLambda, -* RunnableParallel, -* } from "@langchain/core/runnables"; -* -* const addYears = (age: number): number => age + 5; -* const yearsToFifty = (age: number): number => 50 - age; -* const yearsToHundred = (age: number): number => 100 - age; -* -* const addYearsLambda = RunnableLambda.from(addYears); -* const milestoneFiftyLambda = RunnableLambda.from(yearsToFifty); -* const milestoneHundredLambda = RunnableLambda.from(yearsToHundred); -* -* // Pipe will coerce objects into RunnableParallel by default, but we -* // explicitly instantiate one here to demonstrate -* const sequence = addYearsLambda.pipe( -* RunnableParallel.from({ -* years_to_fifty: milestoneFiftyLambda, -* years_to_hundred: milestoneHundredLambda, -* }) -* ); -* -* // Invoke the sequence with a single age input -* const res = await sequence.invoke(25); -* -* // { years_to_fifty: 20, years_to_hundred: 70 } -* ``` -*/ -var RunnableParallel = class extends RunnableMap {}; -/** -* A Runnable that can fallback to other Runnables if it fails. -* External APIs (e.g., APIs for a language model) may at times experience -* degraded performance or even downtime. -* -* In these cases, it can be useful to have a fallback Runnable that can be -* used in place of the original Runnable (e.g., fallback to another LLM provider). -* -* Fallbacks can be defined at the level of a single Runnable, or at the level -* of a chain of Runnables. Fallbacks are tried in order until one succeeds or -* all fail. -* -* While you can instantiate a `RunnableWithFallbacks` directly, it is usually -* more convenient to use the `withFallbacks` method on an existing Runnable. -* -* When streaming, fallbacks will only be called on failures during the initial -* stream creation. Errors that occur after a stream starts will not fallback -* to the next Runnable. -* -* @example -* ```typescript -* import { -* RunnableLambda, -* RunnableWithFallbacks, -* } from "@langchain/core/runnables"; -* -* const primaryOperation = (input: string): string => { -* if (input !== "safe") { -* throw new Error("Primary operation failed due to unsafe input"); -* } -* return `Processed: ${input}`; -* }; -* -* // Define a fallback operation that processes the input differently -* const fallbackOperation = (input: string): string => -* `Fallback processed: ${input}`; -* -* const primaryRunnable = RunnableLambda.from(primaryOperation); -* const fallbackRunnable = RunnableLambda.from(fallbackOperation); -* -* // Apply the fallback logic using the .withFallbacks() method -* const runnableWithFallback = primaryRunnable.withFallbacks([fallbackRunnable]); -* -* // Alternatively, create a RunnableWithFallbacks instance manually -* const manualFallbackChain = new RunnableWithFallbacks({ -* runnable: primaryRunnable, -* fallbacks: [fallbackRunnable], -* }); -* -* // Example invocation using .withFallbacks() -* const res = await runnableWithFallback -* .invoke("unsafe input") -* .catch((error) => { -* console.error("Failed after all attempts:", error.message); -* }); -* -* // "Fallback processed: unsafe input" -* -* // Example invocation using manual instantiation -* const res = await manualFallbackChain -* .invoke("safe") -* .catch((error) => { -* console.error("Failed after all attempts:", error.message); -* }); -* -* // "Processed: safe" -* ``` -*/ -var RunnableWithFallbacks = class extends Runnable { - static lc_name() { - return "RunnableWithFallbacks"; - } - lc_namespace = ["langchain_core", "runnables"]; - lc_serializable = true; - runnable; - fallbacks; - constructor(fields) { - super(fields); - this.runnable = fields.runnable; - this.fallbacks = fields.fallbacks; - } - *runnables() { - yield this.runnable; - for (const fallback of this.fallbacks) yield fallback; - } - async invoke(input, options) { - const config = ensureConfig(options); - const callbackManager_ = await getCallbackManagerForConfig(config); - const { runId,...otherConfigFields } = config; - const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), runId, void 0, void 0, void 0, otherConfigFields?.runName); - const childConfig = config_patchConfig(otherConfigFields, { callbacks: runManager?.getChild() }); - const res = await async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(childConfig, async () => { - let firstError; - for (const runnable of this.runnables()) { - config?.signal?.throwIfAborted(); - try { - const output = await runnable.invoke(input, childConfig); - await runManager?.handleChainEnd(base_coerceToDict(output, "output")); - return output; - } catch (e) { - if (firstError === void 0) firstError = e; - } - } - if (firstError === void 0) throw new Error("No error stored at end of fallback."); - await runManager?.handleChainError(firstError); - throw firstError; - }); - return res; - } - async *_streamIterator(input, options) { - const config = ensureConfig(options); - const callbackManager_ = await getCallbackManagerForConfig(config); - const { runId,...otherConfigFields } = config; - const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), runId, void 0, void 0, void 0, otherConfigFields?.runName); - let firstError; - let stream; - for (const runnable of this.runnables()) { - config?.signal?.throwIfAborted(); - const childConfig = config_patchConfig(otherConfigFields, { callbacks: runManager?.getChild() }); - try { - const originalStream = await runnable.stream(input, childConfig); - stream = consumeAsyncIterableInContext(childConfig, originalStream); - break; - } catch (e) { - if (firstError === void 0) firstError = e; - } - } - if (stream === void 0) { - const error = firstError ?? /* @__PURE__ */ new Error("No error stored at end of fallback."); - await runManager?.handleChainError(error); - throw error; - } - let output; - try { - for await (const chunk of stream) { - yield chunk; - try { - output = output === void 0 ? output : this._concatOutputChunks(output, chunk); - } catch { - output = void 0; - } - } - } catch (e) { - await runManager?.handleChainError(e); - throw e; - } - await runManager?.handleChainEnd(base_coerceToDict(output, "output")); + +//#endregion + +//# sourceMappingURL=catch.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/date.js + + +//#region src/utils/zod-to-json-schema/parsers/date.ts +function parseDateDef(def, refs, overrideDateStrategy) { + const strategy = overrideDateStrategy ?? refs.dateStrategy; + if (Array.isArray(strategy)) return { anyOf: strategy.map((item) => parseDateDef(def, refs, item)) }; + switch (strategy) { + case "string": + case "format:date-time": return { + type: "string", + format: "date-time" + }; + case "format:date": return { + type: "string", + format: "date" + }; + case "integer": return integerDateParser(def, refs); } - async batch(inputs, options, batchOptions) { - if (batchOptions?.returnExceptions) throw new Error("Not implemented."); - const configList = this._getOptionsList(options ?? {}, inputs.length); - const callbackManagers = await Promise.all(configList.map((config) => getCallbackManagerForConfig(config))); - const runManagers = await Promise.all(callbackManagers.map(async (callbackManager, i) => { - const handleStartRes = await callbackManager?.handleChainStart(this.toJSON(), base_coerceToDict(inputs[i], "input"), configList[i].runId, void 0, void 0, void 0, configList[i].runName); - delete configList[i].runId; - return handleStartRes; - })); - let firstError; - for (const runnable of this.runnables()) { - configList[0].signal?.throwIfAborted(); - try { - const outputs = await runnable.batch(inputs, runManagers.map((runManager, j) => config_patchConfig(configList[j], { callbacks: runManager?.getChild() })), batchOptions); - await Promise.all(runManagers.map((runManager, i) => runManager?.handleChainEnd(base_coerceToDict(outputs[i], "output")))); - return outputs; - } catch (e) { - if (firstError === void 0) firstError = e; - } - } - if (!firstError) throw new Error("No error stored at end of fallbacks."); - await Promise.all(runManagers.map((runManager) => runManager?.handleChainError(firstError))); - throw firstError; +} +const integerDateParser = (def, refs) => { + const res = { + type: "integer", + format: "unix-time" + }; + if (refs.target === "openApi3") return res; + for (const check of def.checks) switch (check.kind) { + case "min": + setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); + break; + case "max": + setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); + break; } + return res; }; -function _coerceToRunnable(coerceable) { - if (typeof coerceable === "function") return new RunnableLambda({ func: coerceable }); - else if (Runnable.isRunnable(coerceable)) return coerceable; - else if (!Array.isArray(coerceable) && typeof coerceable === "object") { - const runnables = {}; - for (const [key, value] of Object.entries(coerceable)) runnables[key] = _coerceToRunnable(value); - return new RunnableMap({ steps: runnables }); - } else throw new Error(`Expected a Runnable, function or object.\nInstead got an unsupported type.`); + +//#endregion + +//# sourceMappingURL=date.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/default.js + + +//#region src/utils/zod-to-json-schema/parsers/default.ts +function parseDefaultDef(_def, refs) { + return { + ...parseDef(_def.innerType._def, refs), + default: _def.defaultValue() + }; +} + +//#endregion + +//# sourceMappingURL=default.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/effects.js + + + +//#region src/utils/zod-to-json-schema/parsers/effects.ts +function parseEffectsDef(_def, refs) { + return refs.effectStrategy === "input" ? parseDef(_def.schema._def, refs) : parseAnyDef(refs); +} + +//#endregion + +//# sourceMappingURL=effects.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/enum.js +//#region src/utils/zod-to-json-schema/parsers/enum.ts +function parseEnumDef(def) { + return { + type: "string", + enum: Array.from(def.values) + }; +} + +//#endregion + +//# sourceMappingURL=enum.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/intersection.js + + +//#region src/utils/zod-to-json-schema/parsers/intersection.ts +const isJsonSchema7AllOfType = (type) => { + if ("type" in type && type.type === "string") return false; + return "allOf" in type; +}; +function parseIntersectionDef(def, refs) { + const allOf = [parseDef(def.left._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "allOf", + "0" + ] + }), parseDef(def.right._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "allOf", + "1" + ] + })].filter((x) => !!x); + let unevaluatedProperties = refs.target === "jsonSchema2019-09" ? { unevaluatedProperties: false } : void 0; + const mergedAllOf = []; + allOf.forEach((schema) => { + if (isJsonSchema7AllOfType(schema)) { + mergedAllOf.push(...schema.allOf); + if (schema.unevaluatedProperties === void 0) unevaluatedProperties = void 0; + } else { + let nestedSchema = schema; + if ("additionalProperties" in schema && schema.additionalProperties === false) { + const { additionalProperties,...rest } = schema; + nestedSchema = rest; + } else unevaluatedProperties = void 0; + mergedAllOf.push(nestedSchema); + } + }); + return mergedAllOf.length ? { + allOf: mergedAllOf, + ...unevaluatedProperties + } : void 0; +} + +//#endregion + +//# sourceMappingURL=intersection.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/literal.js +//#region src/utils/zod-to-json-schema/parsers/literal.ts +function parseLiteralDef(def, refs) { + const parsedType = typeof def.value; + if (parsedType !== "bigint" && parsedType !== "number" && parsedType !== "boolean" && parsedType !== "string") return { type: Array.isArray(def.value) ? "array" : "object" }; + if (refs.target === "openApi3") return { + type: parsedType === "bigint" ? "integer" : parsedType, + enum: [def.value] + }; + return { + type: parsedType === "bigint" ? "integer" : parsedType, + const: def.value + }; } + +//#endregion + +//# sourceMappingURL=literal.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/string.js + + +//#region src/utils/zod-to-json-schema/parsers/string.ts +let string_emojiRegex = void 0; /** -* A runnable that assigns key-value pairs to inputs of type `Record`. -* @example -* ```typescript -* import { -* RunnableAssign, -* RunnableLambda, -* RunnableParallel, -* } from "@langchain/core/runnables"; -* -* const calculateAge = (x: { birthYear: number }): { age: number } => { -* const currentYear = new Date().getFullYear(); -* return { age: currentYear - x.birthYear }; -* }; -* -* const createGreeting = (x: { name: string }): { greeting: string } => { -* return { greeting: `Hello, ${x.name}!` }; -* }; -* -* const mapper = RunnableParallel.from({ -* age_step: RunnableLambda.from(calculateAge), -* greeting_step: RunnableLambda.from(createGreeting), -* }); -* -* const runnableAssign = new RunnableAssign({ mapper }); -* -* const res = await runnableAssign.invoke({ name: "Alice", birthYear: 1990 }); +* Generated from the regular expressions found here as of 2024-05-22: +* https://github.com/colinhacks/zod/blob/master/src/types.ts. * -* // { name: "Alice", birthYear: 1990, age_step: { age: 34 }, greeting_step: { greeting: "Hello, Alice!" } } -* ``` +* Expressions with /i flag have been changed accordingly. */ -var RunnableAssign = class extends Runnable { - static lc_name() { - return "RunnableAssign"; - } - lc_namespace = ["langchain_core", "runnables"]; - lc_serializable = true; - mapper; - constructor(fields) { - if (fields instanceof RunnableMap) fields = { mapper: fields }; - super(fields); - this.mapper = fields.mapper; - } - async invoke(input, options) { - const mapperResult = await this.mapper.invoke(input, options); - return { - ...input, - ...mapperResult - }; - } - async *_transform(generator, runManager, options) { - const mapperKeys = this.mapper.getStepsKeys(); - const [forPassthrough, forMapper] = atee(generator); - const mapperOutput = this.mapper.transform(forMapper, config_patchConfig(options, { callbacks: runManager?.getChild() })); - const firstMapperChunkPromise = mapperOutput.next(); - for await (const chunk of forPassthrough) { - if (typeof chunk !== "object" || Array.isArray(chunk)) throw new Error(`RunnableAssign can only be used with objects as input, got ${typeof chunk}`); - const filtered = Object.fromEntries(Object.entries(chunk).filter(([key]) => !mapperKeys.includes(key))); - if (Object.keys(filtered).length > 0) yield filtered; - } - yield (await firstMapperChunkPromise).value; - for await (const chunk of mapperOutput) yield chunk; +const zodPatterns = { + cuid: /^[cC][^\s-]{8,}$/, + cuid2: /^[0-9a-z]+$/, + ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/, + email: /^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/, + emoji: () => { + if (string_emojiRegex === void 0) string_emojiRegex = RegExp("^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$", "u"); + return string_emojiRegex; + }, + uuid: /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/, + ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/, + ipv4Cidr: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/, + ipv6: /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/, + ipv6Cidr: /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/, + base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/, + base64url: /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/, + nanoid: /^[a-zA-Z0-9_-]{21}$/, + jwt: /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/ +}; +function parseStringDef(def, refs) { + const res = { type: "string" }; + if (def.checks) for (const check of def.checks) switch (check.kind) { + case "min": + setResponseValueAndErrors(res, "minLength", typeof res.minLength === "number" ? Math.max(res.minLength, check.value) : check.value, check.message, refs); + break; + case "max": + setResponseValueAndErrors(res, "maxLength", typeof res.maxLength === "number" ? Math.min(res.maxLength, check.value) : check.value, check.message, refs); + break; + case "email": + switch (refs.emailStrategy) { + case "format:email": + addFormat(res, "email", check.message, refs); + break; + case "format:idn-email": + addFormat(res, "idn-email", check.message, refs); + break; + case "pattern:zod": + addPattern(res, zodPatterns.email, check.message, refs); + break; + } + break; + case "url": + addFormat(res, "uri", check.message, refs); + break; + case "uuid": + addFormat(res, "uuid", check.message, refs); + break; + case "regex": + addPattern(res, check.regex, check.message, refs); + break; + case "cuid": + addPattern(res, zodPatterns.cuid, check.message, refs); + break; + case "cuid2": + addPattern(res, zodPatterns.cuid2, check.message, refs); + break; + case "startsWith": + addPattern(res, RegExp(`^${escapeLiteralCheckValue(check.value, refs)}`), check.message, refs); + break; + case "endsWith": + addPattern(res, RegExp(`${escapeLiteralCheckValue(check.value, refs)}$`), check.message, refs); + break; + case "datetime": + addFormat(res, "date-time", check.message, refs); + break; + case "date": + addFormat(res, "date", check.message, refs); + break; + case "time": + addFormat(res, "time", check.message, refs); + break; + case "duration": + addFormat(res, "duration", check.message, refs); + break; + case "length": + setResponseValueAndErrors(res, "minLength", typeof res.minLength === "number" ? Math.max(res.minLength, check.value) : check.value, check.message, refs); + setResponseValueAndErrors(res, "maxLength", typeof res.maxLength === "number" ? Math.min(res.maxLength, check.value) : check.value, check.message, refs); + break; + case "includes": + addPattern(res, RegExp(escapeLiteralCheckValue(check.value, refs)), check.message, refs); + break; + case "ip": + if (check.version !== "v6") addFormat(res, "ipv4", check.message, refs); + if (check.version !== "v4") addFormat(res, "ipv6", check.message, refs); + break; + case "base64url": + addPattern(res, zodPatterns.base64url, check.message, refs); + break; + case "jwt": + addPattern(res, zodPatterns.jwt, check.message, refs); + break; + case "cidr": + if (check.version !== "v6") addPattern(res, zodPatterns.ipv4Cidr, check.message, refs); + if (check.version !== "v4") addPattern(res, zodPatterns.ipv6Cidr, check.message, refs); + break; + case "emoji": + addPattern(res, zodPatterns.emoji(), check.message, refs); + break; + case "ulid": + addPattern(res, zodPatterns.ulid, check.message, refs); + break; + case "base64": + switch (refs.base64Strategy) { + case "format:binary": + addFormat(res, "binary", check.message, refs); + break; + case "contentEncoding:base64": + setResponseValueAndErrors(res, "contentEncoding", "base64", check.message, refs); + break; + case "pattern:zod": + addPattern(res, zodPatterns.base64, check.message, refs); + break; + } + break; + case "nanoid": + addPattern(res, zodPatterns.nanoid, check.message, refs); + break; + case "toLowerCase": + case "toUpperCase": + case "trim": break; + default: + /* c8 ignore next */ + ((_) => {})(check); } - transform(generator, options) { - return this._transformStreamWithConfig(generator, this._transform.bind(this), options); + return res; +} +function escapeLiteralCheckValue(literal, refs) { + return refs.patternStrategy === "escape" ? escapeNonAlphaNumeric(literal) : literal; +} +const ALPHA_NUMERIC = /* @__PURE__ */ new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789"); +function escapeNonAlphaNumeric(source) { + let result = ""; + for (let i = 0; i < source.length; i++) { + if (!ALPHA_NUMERIC.has(source[i])) result += "\\"; + result += source[i]; } - async stream(input, options) { - async function* generator() { - yield input; + return result; +} +function addFormat(schema, value, message, refs) { + if (schema.format || schema.anyOf?.some((x) => x.format)) { + if (!schema.anyOf) schema.anyOf = []; + if (schema.format) { + schema.anyOf.push({ + format: schema.format, + ...schema.errorMessage && refs.errorMessages && { errorMessage: { format: schema.errorMessage.format } } + }); + delete schema.format; + if (schema.errorMessage) { + delete schema.errorMessage.format; + if (Object.keys(schema.errorMessage).length === 0) delete schema.errorMessage; + } } - const config = ensureConfig(options); - const wrappedGenerator = new AsyncGeneratorWithSetup({ - generator: this.transform(generator(), config), - config + schema.anyOf.push({ + format: value, + ...message && refs.errorMessages && { errorMessage: { format: message } } }); - await wrappedGenerator.setup; - return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); - } -}; -/** -* A runnable that assigns key-value pairs to inputs of type `Record`. -* Useful for streaming, can be automatically created and chained by calling `runnable.pick();`. -* @example -* ```typescript -* import { RunnablePick } from "@langchain/core/runnables"; -* -* const inputData = { -* name: "John", -* age: 30, -* city: "New York", -* country: "USA", -* email: "john.doe@example.com", -* phone: "+1234567890", -* }; -* -* const basicInfoRunnable = new RunnablePick(["name", "city"]); -* -* // Example invocation -* const res = await basicInfoRunnable.invoke(inputData); -* -* // { name: 'John', city: 'New York' } -* ``` -*/ -var RunnablePick = class extends Runnable { - static lc_name() { - return "RunnablePick"; - } - lc_namespace = ["langchain_core", "runnables"]; - lc_serializable = true; - keys; - constructor(fields) { - if (typeof fields === "string" || Array.isArray(fields)) fields = { keys: fields }; - super(fields); - this.keys = fields.keys; - } - async _pick(input) { - if (typeof this.keys === "string") return input[this.keys]; - else { - const picked = this.keys.map((key) => [key, input[key]]).filter((v) => v[1] !== void 0); - return picked.length === 0 ? void 0 : Object.fromEntries(picked); + } else setResponseValueAndErrors(schema, "format", value, message, refs); +} +function addPattern(schema, regex, message, refs) { + if (schema.pattern || schema.allOf?.some((x) => x.pattern)) { + if (!schema.allOf) schema.allOf = []; + if (schema.pattern) { + schema.allOf.push({ + pattern: schema.pattern, + ...schema.errorMessage && refs.errorMessages && { errorMessage: { pattern: schema.errorMessage.pattern } } + }); + delete schema.pattern; + if (schema.errorMessage) { + delete schema.errorMessage.pattern; + if (Object.keys(schema.errorMessage).length === 0) delete schema.errorMessage; + } } - } - async invoke(input, options) { - return this._callWithConfig(this._pick.bind(this), input, options); - } - async *_transform(generator) { - for await (const chunk of generator) { - const picked = await this._pick(chunk); - if (picked !== void 0) yield picked; + schema.allOf.push({ + pattern: stringifyRegExpWithFlags(regex, refs), + ...message && refs.errorMessages && { errorMessage: { pattern: message } } + }); + } else setResponseValueAndErrors(schema, "pattern", stringifyRegExpWithFlags(regex, refs), message, refs); +} +function stringifyRegExpWithFlags(regex, refs) { + if (!refs.applyRegexFlags || !regex.flags) return regex.source; + const flags = { + i: regex.flags.includes("i"), + m: regex.flags.includes("m"), + s: regex.flags.includes("s") + }; + const source = flags.i ? regex.source.toLowerCase() : regex.source; + let pattern = ""; + let isEscaped = false; + let inCharGroup = false; + let inCharRange = false; + for (let i = 0; i < source.length; i++) { + if (isEscaped) { + pattern += source[i]; + isEscaped = false; + continue; } - } - transform(generator, options) { - return this._transformStreamWithConfig(generator, this._transform.bind(this), options); - } - async stream(input, options) { - async function* generator() { - yield input; + if (flags.i) { + if (inCharGroup) { + if (source[i].match(/[a-z]/)) { + if (inCharRange) { + pattern += source[i]; + pattern += `${source[i - 2]}-${source[i]}`.toUpperCase(); + inCharRange = false; + } else if (source[i + 1] === "-" && source[i + 2]?.match(/[a-z]/)) { + pattern += source[i]; + inCharRange = true; + } else pattern += `${source[i]}${source[i].toUpperCase()}`; + continue; + } + } else if (source[i].match(/[a-z]/)) { + pattern += `[${source[i]}${source[i].toUpperCase()}]`; + continue; + } } - const config = ensureConfig(options); - const wrappedGenerator = new AsyncGeneratorWithSetup({ - generator: this.transform(generator(), config), - config - }); - await wrappedGenerator.setup; - return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); - } -}; -var RunnableToolLike = class extends RunnableBinding { - name; - description; - schema; - constructor(fields) { - const sequence = RunnableSequence.from([RunnableLambda.from(async (input) => { - let toolInput; - if (_isToolCall(input)) try { - toolInput = await interopParseAsync(this.schema, input.args); - } catch { - throw new ToolInputParsingException(`Received tool input did not match expected schema`, JSON.stringify(input.args)); + if (flags.m) { + if (source[i] === "^") { + pattern += `(^|(?<=[\r\n]))`; + continue; + } else if (source[i] === "$") { + pattern += `($|(?=[\r\n]))`; + continue; } - else toolInput = input; - return toolInput; - }).withConfig({ runName: `${fields.name}:parse_input` }), fields.bound]).withConfig({ runName: fields.name }); - super({ - bound: sequence, - config: fields.config ?? {} - }); - this.name = fields.name; - this.description = fields.description; - this.schema = fields.schema; + } + if (flags.s && source[i] === ".") { + pattern += inCharGroup ? `${source[i]}\r\n` : `[${source[i]}\r\n]`; + continue; + } + pattern += source[i]; + if (source[i] === "\\") isEscaped = true; + else if (inCharGroup && source[i] === "]") inCharGroup = false; + else if (!inCharGroup && source[i] === "[") inCharGroup = true; } - static lc_name() { - return "RunnableToolLike"; + try { + new RegExp(pattern); + } catch { + console.warn(`Could not convert regex pattern at ${refs.currentPath.join("/")} to a flag-independent form! Falling back to the flag-ignorant source`); + return regex.source; } -}; -/** -* Given a runnable and a Zod schema, convert the runnable to a tool. -* -* @template RunInput The input type for the runnable. -* @template RunOutput The output type for the runnable. -* -* @param {Runnable} runnable The runnable to convert to a tool. -* @param fields -* @param {string | undefined} [fields.name] The name of the tool. If not provided, it will default to the name of the runnable. -* @param {string | undefined} [fields.description] The description of the tool. Falls back to the description on the Zod schema if not provided, or undefined if neither are provided. -* @param {InteropZodType} [fields.schema] The Zod schema for the input of the tool. Infers the Zod type from the input type of the runnable. -* @returns {RunnableToolLike, RunOutput>} An instance of `RunnableToolLike` which is a runnable that can be used as a tool. -*/ -function convertRunnableToTool(runnable, fields) { - const name = fields.name ?? runnable.getName(); - const description = fields.description ?? getSchemaDescription(fields.schema); - if (isSimpleStringZodSchema(fields.schema)) return new RunnableToolLike({ - name, - description, - schema: objectType({ input: stringType() }).transform((input) => input.input), - bound: runnable - }); - return new RunnableToolLike({ - name, - description, - schema: fields.schema, - bound: runnable - }); + return pattern; } //#endregion -//# sourceMappingURL=base.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/transformers.js +//# sourceMappingURL=string.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/record.js +//#region src/utils/zod-to-json-schema/parsers/record.ts +function parseRecordDef(def, refs) { + if (refs.target === "openAi") console.warn("Warning: OpenAI may not support records in schemas! Try an array of key-value pairs instead."); + if (refs.target === "openApi3" && def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) return { + type: "object", + required: def.keyType._def.values, + properties: def.keyType._def.values.reduce((acc, key) => ({ + ...acc, + [key]: parseDef(def.valueType._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "properties", + key + ] + }) ?? parseAnyDef(refs) + }), {}), + additionalProperties: refs.rejectedAdditionalProperties + }; + const schema = { + type: "object", + additionalProperties: parseDef(def.valueType._def, { + ...refs, + currentPath: [...refs.currentPath, "additionalProperties"] + }) ?? refs.allowedAdditionalProperties + }; + if (refs.target === "openApi3") return schema; + if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodString && def.keyType._def.checks?.length) { + const { type,...keyType } = parseStringDef(def.keyType._def, refs); + return { + ...schema, + propertyNames: keyType + }; + } else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) return { + ...schema, + propertyNames: { enum: def.keyType._def.values } + }; + else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodBranded && def.keyType._def.type._def.typeName === ZodFirstPartyTypeKind.ZodString && def.keyType._def.type._def.checks?.length) { + const { type,...keyType } = parseBrandedDef(def.keyType._def, refs); + return { + ...schema, + propertyNames: keyType + }; + } + return schema; +} +//#endregion +//# sourceMappingURL=record.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/map.js -//#region src/messages/transformers.ts -const _isMessageType = (msg, types) => { - const typesAsStrings = [...new Set(types?.map((t) => { - if (typeof t === "string") return t; - const instantiatedMsgClass = new t({}); - if (!("getType" in instantiatedMsgClass) || typeof instantiatedMsgClass.getType !== "function") throw new Error("Invalid type provided."); - return instantiatedMsgClass.getType(); - }))]; - const msgType = msg.getType(); - return typesAsStrings.some((t) => t === msgType); -}; -function filterMessages(messagesOrOptions, options) { - if (Array.isArray(messagesOrOptions)) return _filterMessages(messagesOrOptions, options); - return RunnableLambda.from((input) => { - return _filterMessages(input, messagesOrOptions); - }); -} -function _filterMessages(messages, options = {}) { - const { includeNames, excludeNames, includeTypes, excludeTypes, includeIds, excludeIds } = options; - const filtered = []; - for (const msg of messages) { - if (excludeNames && msg.name && excludeNames.includes(msg.name)) continue; - else if (excludeTypes && _isMessageType(msg, excludeTypes)) continue; - else if (excludeIds && msg.id && excludeIds.includes(msg.id)) continue; - if (!(includeTypes || includeIds || includeNames)) filtered.push(msg); - else if (includeNames && msg.name && includeNames.some((iName) => iName === msg.name)) filtered.push(msg); - else if (includeTypes && _isMessageType(msg, includeTypes)) filtered.push(msg); - else if (includeIds && msg.id && includeIds.some((id) => id === msg.id)) filtered.push(msg); - } - return filtered; -} -function mergeMessageRuns(messages) { - if (Array.isArray(messages)) return _mergeMessageRuns(messages); - return RunnableLambda.from(_mergeMessageRuns); -} -function _mergeMessageRuns(messages) { - if (!messages.length) return []; - const merged = []; - for (const msg of messages) { - const curr = msg; - const last = merged.pop(); - if (!last) merged.push(curr); - else if (curr.getType() === "tool" || !(curr.getType() === last.getType())) merged.push(last, curr); - else { - const lastChunk = convertToChunk(last); - const currChunk = convertToChunk(curr); - const mergedChunks = lastChunk.concat(currChunk); - if (typeof lastChunk.content === "string" && typeof currChunk.content === "string") mergedChunks.content = `${lastChunk.content}\n${currChunk.content}`; - merged.push(_chunkToMsg(mergedChunks)); + +//#region src/utils/zod-to-json-schema/parsers/map.ts +function parseMapDef(def, refs) { + if (refs.mapStrategy === "record") return parseRecordDef(def, refs); + const keys = parseDef(def.keyType._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "items", + "items", + "0" + ] + }) || parseAnyDef(refs); + const values = parseDef(def.valueType._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "items", + "items", + "1" + ] + }) || parseAnyDef(refs); + return { + type: "array", + maxItems: 125, + items: { + type: "array", + items: [keys, values], + minItems: 2, + maxItems: 2 } - } - return merged; -} -function trimMessages(messagesOrOptions, options) { - if (Array.isArray(messagesOrOptions)) { - const messages = messagesOrOptions; - if (!options) throw new Error("Options parameter is required when providing messages."); - return _trimMessagesHelper(messages, options); - } else { - const trimmerOptions = messagesOrOptions; - return RunnableLambda.from((input) => _trimMessagesHelper(input, trimmerOptions)).withConfig({ runName: "trim_messages" }); - } -} -async function _trimMessagesHelper(messages, options) { - const { maxTokens, tokenCounter, strategy = "last", allowPartial = false, endOn, startOn, includeSystem = false, textSplitter } = options; - if (startOn && strategy === "first") throw new Error("`startOn` should only be specified if `strategy` is 'last'."); - if (includeSystem && strategy === "first") throw new Error("`includeSystem` should only be specified if `strategy` is 'last'."); - let listTokenCounter; - if ("getNumTokens" in tokenCounter) listTokenCounter = async (msgs) => { - const tokenCounts = await Promise.all(msgs.map((msg) => tokenCounter.getNumTokens(msg.content))); - return tokenCounts.reduce((sum, count) => sum + count, 0); }; - else listTokenCounter = async (msgs) => tokenCounter(msgs); - let textSplitterFunc = defaultTextSplitter; - if (textSplitter) if ("splitText" in textSplitter) textSplitterFunc = textSplitter.splitText; - else textSplitterFunc = async (text) => textSplitter(text); - if (strategy === "first") return _firstMaxTokens(messages, { - maxTokens, - tokenCounter: listTokenCounter, - textSplitter: textSplitterFunc, - partialStrategy: allowPartial ? "first" : void 0, - endOn - }); - else if (strategy === "last") return _lastMaxTokens(messages, { - maxTokens, - tokenCounter: listTokenCounter, - textSplitter: textSplitterFunc, - allowPartial, - includeSystem, - startOn, - endOn - }); - else throw new Error(`Unrecognized strategy: '${strategy}'. Must be one of 'first' or 'last'.`); -} -async function _firstMaxTokens(messages, options) { - const { maxTokens, tokenCounter, textSplitter, partialStrategy, endOn } = options; - let messagesCopy = [...messages]; - let idx = 0; - for (let i = 0; i < messagesCopy.length; i += 1) { - const remainingMessages = i > 0 ? messagesCopy.slice(0, -i) : messagesCopy; - if (await tokenCounter(remainingMessages) <= maxTokens) { - idx = messagesCopy.length - i; - break; - } - } - if (idx < messagesCopy.length && partialStrategy) { - let includedPartial = false; - if (Array.isArray(messagesCopy[idx].content)) { - const excluded = messagesCopy[idx]; - if (typeof excluded.content === "string") throw new Error("Expected content to be an array."); - const numBlock = excluded.content.length; - const reversedContent = partialStrategy === "last" ? [...excluded.content].reverse() : excluded.content; - for (let i = 1; i <= numBlock; i += 1) { - const partialContent = partialStrategy === "first" ? reversedContent.slice(0, i) : reversedContent.slice(-i); - const fields = Object.fromEntries(Object.entries(excluded).filter(([k]) => k !== "type" && !k.startsWith("lc_"))); - const updatedMessage = _switchTypeToMessage(excluded.getType(), { - ...fields, - content: partialContent - }); - const slicedMessages = [...messagesCopy.slice(0, idx), updatedMessage]; - if (await tokenCounter(slicedMessages) <= maxTokens) { - messagesCopy = slicedMessages; - idx += 1; - includedPartial = true; - } else break; - } - if (includedPartial && partialStrategy === "last") excluded.content = [...reversedContent].reverse(); - } - if (!includedPartial) { - const excluded = messagesCopy[idx]; - let text; - if (Array.isArray(excluded.content) && excluded.content.some((block) => typeof block === "string" || block.type === "text")) { - const textBlock = excluded.content.find((block) => block.type === "text" && block.text); - text = textBlock?.text; - } else if (typeof excluded.content === "string") text = excluded.content; - if (text) { - const splitTexts = await textSplitter(text); - const numSplits = splitTexts.length; - if (partialStrategy === "last") splitTexts.reverse(); - for (let _ = 0; _ < numSplits - 1; _ += 1) { - splitTexts.pop(); - excluded.content = splitTexts.join(""); - if (await tokenCounter([...messagesCopy.slice(0, idx), excluded]) <= maxTokens) { - if (partialStrategy === "last") excluded.content = [...splitTexts].reverse().join(""); - messagesCopy = [...messagesCopy.slice(0, idx), excluded]; - idx += 1; - break; - } - } - } - } - } - if (endOn) { - const endOnArr = Array.isArray(endOn) ? endOn : [endOn]; - while (idx > 0 && !_isMessageType(messagesCopy[idx - 1], endOnArr)) idx -= 1; - } - return messagesCopy.slice(0, idx); } -async function _lastMaxTokens(messages, options) { - const { allowPartial = false, includeSystem = false, endOn, startOn,...rest } = options; - let messagesCopy = messages.map((message) => { - const fields = Object.fromEntries(Object.entries(message).filter(([k]) => k !== "type" && !k.startsWith("lc_"))); - return _switchTypeToMessage(message.getType(), fields, isBaseMessageChunk(message)); - }); - if (endOn) { - const endOnArr = Array.isArray(endOn) ? endOn : [endOn]; - while (messagesCopy.length > 0 && !_isMessageType(messagesCopy[messagesCopy.length - 1], endOnArr)) messagesCopy = messagesCopy.slice(0, -1); - } - const swappedSystem = includeSystem && messagesCopy[0]?.getType() === "system"; - let reversed_ = swappedSystem ? messagesCopy.slice(0, 1).concat(messagesCopy.slice(1).reverse()) : messagesCopy.reverse(); - reversed_ = await _firstMaxTokens(reversed_, { - ...rest, - partialStrategy: allowPartial ? "last" : void 0, - endOn: startOn + +//#endregion + +//# sourceMappingURL=map.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/nativeEnum.js +//#region src/utils/zod-to-json-schema/parsers/nativeEnum.ts +function parseNativeEnumDef(def) { + const object = def.values; + const actualKeys = Object.keys(def.values).filter((key) => { + return typeof object[object[key]] !== "number"; }); - if (swappedSystem) return [reversed_[0], ...reversed_.slice(1).reverse()]; - else return reversed_.reverse(); -} -const _MSG_CHUNK_MAP = { - human: { - message: HumanMessage, - messageChunk: HumanMessageChunk - }, - ai: { - message: AIMessage, - messageChunk: AIMessageChunk - }, - system: { - message: SystemMessage, - messageChunk: SystemMessageChunk - }, - developer: { - message: SystemMessage, - messageChunk: SystemMessageChunk - }, - tool: { - message: ToolMessage, - messageChunk: ToolMessageChunk - }, - function: { - message: FunctionMessage, - messageChunk: FunctionMessageChunk - }, - generic: { - message: ChatMessage, - messageChunk: ChatMessageChunk - }, - remove: { - message: RemoveMessage, - messageChunk: RemoveMessage - } -}; -function _switchTypeToMessage(messageType, fields, returnChunk) { - let chunk; - let msg; - switch (messageType) { - case "human": - if (returnChunk) chunk = new HumanMessageChunk(fields); - else msg = new HumanMessage(fields); - break; - case "ai": - if (returnChunk) { - let aiChunkFields = { ...fields }; - if ("tool_calls" in aiChunkFields) aiChunkFields = { - ...aiChunkFields, - tool_call_chunks: aiChunkFields.tool_calls?.map((tc) => ({ - ...tc, - type: "tool_call_chunk", - index: void 0, - args: JSON.stringify(tc.args) - })) - }; - chunk = new AIMessageChunk(aiChunkFields); - } else msg = new AIMessage(fields); - break; - case "system": - if (returnChunk) chunk = new SystemMessageChunk(fields); - else msg = new SystemMessage(fields); - break; - case "developer": - if (returnChunk) chunk = new SystemMessageChunk({ - ...fields, - additional_kwargs: { - ...fields.additional_kwargs, - __openai_role__: "developer" - } - }); - else msg = new SystemMessage({ - ...fields, - additional_kwargs: { - ...fields.additional_kwargs, - __openai_role__: "developer" - } - }); - break; - case "tool": - if ("tool_call_id" in fields) if (returnChunk) chunk = new ToolMessageChunk(fields); - else msg = new ToolMessage(fields); - else throw new Error("Can not convert ToolMessage to ToolMessageChunk if 'tool_call_id' field is not defined."); - break; - case "function": - if (returnChunk) chunk = new FunctionMessageChunk(fields); - else { - if (!fields.name) throw new Error("FunctionMessage must have a 'name' field"); - msg = new FunctionMessage(fields); - } - break; - case "generic": - if ("role" in fields) if (returnChunk) chunk = new ChatMessageChunk(fields); - else msg = new ChatMessage(fields); - else throw new Error("Can not convert ChatMessage to ChatMessageChunk if 'role' field is not defined."); - break; - default: throw new Error(`Unrecognized message type ${messageType}`); - } - if (returnChunk && chunk) return chunk; - if (msg) return msg; - throw new Error(`Unrecognized message type ${messageType}`); -} -function _chunkToMsg(chunk) { - const chunkType = chunk.getType(); - let msg; - const fields = Object.fromEntries(Object.entries(chunk).filter(([k]) => !["type", "tool_call_chunks"].includes(k) && !k.startsWith("lc_"))); - if (chunkType in _MSG_CHUNK_MAP) msg = _switchTypeToMessage(chunkType, fields); - if (!msg) throw new Error(`Unrecognized message chunk class ${chunkType}. Supported classes are ${Object.keys(_MSG_CHUNK_MAP)}`); - return msg; + const actualValues = actualKeys.map((key) => object[key]); + const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values))); + return { + type: parsedTypes.length === 1 ? parsedTypes[0] === "string" ? "string" : "number" : ["string", "number"], + enum: actualValues + }; } -/** -* The default text splitter function that splits text by newlines. -* -* @param {string} text -* @returns A promise that resolves to an array of strings split by newlines. -*/ -function defaultTextSplitter(text) { - const splits = text.split("\n"); - return Promise.resolve([...splits.slice(0, -1).map((s) => `${s}\n`), splits[splits.length - 1]]); + +//#endregion + +//# sourceMappingURL=nativeEnum.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/never.js + + +//#region src/utils/zod-to-json-schema/parsers/never.ts +function parseNeverDef(refs) { + return refs.target === "openAi" ? void 0 : { not: parseAnyDef({ + ...refs, + currentPath: [...refs.currentPath, "not"] + }) }; } //#endregion -//# sourceMappingURL=transformers.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/content/tools.js -//#region src/messages/content/tools.ts -const KNOWN_BLOCK_TYPES = [ - "tool_call", - "tool_call_chunk", - "invalid_tool_call", - "server_tool_call", - "server_tool_call_chunk", - "server_tool_call_result" -]; +//# sourceMappingURL=never.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/null.js +//#region src/utils/zod-to-json-schema/parsers/null.ts +function parseNullDef(refs) { + return refs.target === "openApi3" ? { + enum: ["null"], + nullable: true + } : { type: "null" }; +} //#endregion -//# sourceMappingURL=tools.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/content/multimodal.js -//#region src/messages/content/multimodal.ts -const multimodal_KNOWN_BLOCK_TYPES = [ - "image", - "video", - "audio", - "text-plain", - "file" -]; +//# sourceMappingURL=null.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/union.js + + +//#region src/utils/zod-to-json-schema/parsers/union.ts +const primitiveMappings = { + ZodString: "string", + ZodNumber: "number", + ZodBigInt: "integer", + ZodBoolean: "boolean", + ZodNull: "null" +}; +function parseUnionDef(def, refs) { + if (refs.target === "openApi3") return asAnyOf(def, refs); + const options = def.options instanceof Map ? Array.from(def.options.values()) : def.options; + if (options.every((x) => x._def.typeName in primitiveMappings && (!x._def.checks || !x._def.checks.length))) { + const types = options.reduce((types$1, x) => { + const type = primitiveMappings[x._def.typeName]; + return type && !types$1.includes(type) ? [...types$1, type] : types$1; + }, []); + return { type: types.length > 1 ? types : types[0] }; + } else if (options.every((x) => x._def.typeName === "ZodLiteral" && !x.description)) { + const types = options.reduce((acc, x) => { + const type = typeof x._def.value; + switch (type) { + case "string": + case "number": + case "boolean": return [...acc, type]; + case "bigint": return [...acc, "integer"]; + case "object": + if (x._def.value === null) return [...acc, "null"]; + return acc; + case "symbol": + case "undefined": + case "function": + default: return acc; + } + }, []); + if (types.length === options.length) { + const uniqueTypes = types.filter((x, i, a) => a.indexOf(x) === i); + return { + type: uniqueTypes.length > 1 ? uniqueTypes : uniqueTypes[0], + enum: options.reduce((acc, x) => { + return acc.includes(x._def.value) ? acc : [...acc, x._def.value]; + }, []) + }; + } + } else if (options.every((x) => x._def.typeName === "ZodEnum")) return { + type: "string", + enum: options.reduce((acc, x) => [...acc, ...x._def.values.filter((x$1) => !acc.includes(x$1))], []) + }; + return asAnyOf(def, refs); +} +const asAnyOf = (def, refs) => { + const anyOf = (def.options instanceof Map ? Array.from(def.options.values()) : def.options).map((x, i) => parseDef(x._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "anyOf", + `${i}` + ] + })).filter((x) => !!x && (!refs.strictUnions || typeof x === "object" && Object.keys(x).length > 0)); + return anyOf.length ? { anyOf } : void 0; +}; //#endregion -//# sourceMappingURL=multimodal.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/content/index.js +//# sourceMappingURL=union.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/nullable.js -//#region src/messages/content/index.ts -const KNOWN_BLOCK_TYPES$2 = [ - "text", - "reasoning", - ...KNOWN_BLOCK_TYPES, - ...multimodal_KNOWN_BLOCK_TYPES -]; +//#region src/utils/zod-to-json-schema/parsers/nullable.ts +function parseNullableDef(def, refs) { + if ([ + "ZodString", + "ZodNumber", + "ZodBigInt", + "ZodBoolean", + "ZodNull" + ].includes(def.innerType._def.typeName) && (!def.innerType._def.checks || !def.innerType._def.checks.length)) { + if (refs.target === "openApi3") return { + type: primitiveMappings[def.innerType._def.typeName], + nullable: true + }; + return { type: [primitiveMappings[def.innerType._def.typeName], "null"] }; + } + if (refs.target === "openApi3") { + const base$1 = parseDef(def.innerType._def, { + ...refs, + currentPath: [...refs.currentPath] + }); + if (base$1 && "$ref" in base$1) return { + allOf: [base$1], + nullable: true + }; + return base$1 && { + ...base$1, + nullable: true + }; + } + const base = parseDef(def.innerType._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "anyOf", + "0" + ] + }); + return base && { anyOf: [base, { type: "null" }] }; +} //#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/index.js - - - - - +//# sourceMappingURL=nullable.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/number.js +//#region src/utils/zod-to-json-schema/parsers/number.ts +function parseNumberDef(def, refs) { + const res = { type: "number" }; + if (!def.checks) return res; + for (const check of def.checks) switch (check.kind) { + case "int": + res.type = "integer"; + addErrorMessage(res, "type", check.message, refs); + break; + case "min": + if (refs.target === "jsonSchema7") if (check.inclusive) setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); + else setResponseValueAndErrors(res, "exclusiveMinimum", check.value, check.message, refs); + else { + if (!check.inclusive) res.exclusiveMinimum = true; + setResponseValueAndErrors(res, "minimum", check.value, check.message, refs); + } + break; + case "max": + if (refs.target === "jsonSchema7") if (check.inclusive) setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); + else setResponseValueAndErrors(res, "exclusiveMaximum", check.value, check.message, refs); + else { + if (!check.inclusive) res.exclusiveMaximum = true; + setResponseValueAndErrors(res, "maximum", check.value, check.message, refs); + } + break; + case "multipleOf": + setResponseValueAndErrors(res, "multipleOf", check.value, check.message, refs); + break; + } + return res; +} +//#endregion +//# sourceMappingURL=number.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/object.js +//#region src/utils/zod-to-json-schema/parsers/object.ts +function parseObjectDef(def, refs) { + const forceOptionalIntoNullable = refs.target === "openAi"; + const result = { + type: "object", + properties: {} + }; + const required = []; + const shape = def.shape(); + for (const propName in shape) { + let propDef = shape[propName]; + if (propDef === void 0 || propDef._def === void 0) continue; + let propOptional = safeIsOptional(propDef); + if (propOptional && forceOptionalIntoNullable) { + if (propDef._def.typeName === "ZodOptional") propDef = propDef._def.innerType; + if (!propDef.isNullable()) propDef = propDef.nullable(); + propOptional = false; + } + const parsedDef = parseDef(propDef._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "properties", + propName + ], + propertyPath: [ + ...refs.currentPath, + "properties", + propName + ] + }); + if (parsedDef === void 0) continue; + result.properties[propName] = parsedDef; + if (!propOptional) required.push(propName); + } + if (required.length) result.required = required; + const additionalProperties = decideAdditionalProperties(def, refs); + if (additionalProperties !== void 0) result.additionalProperties = additionalProperties; + return result; +} +function decideAdditionalProperties(def, refs) { + if (def.catchall._def.typeName !== "ZodNever") return parseDef(def.catchall._def, { + ...refs, + currentPath: [...refs.currentPath, "additionalProperties"] + }); + switch (def.unknownKeys) { + case "passthrough": return refs.allowedAdditionalProperties; + case "strict": return refs.rejectedAdditionalProperties; + case "strip": return refs.removeAdditionalStrategy === "strict" ? refs.allowedAdditionalProperties : refs.rejectedAdditionalProperties; + } +} +function safeIsOptional(schema) { + try { + return schema.isOptional(); + } catch { + return true; + } +} +//#endregion +//# sourceMappingURL=object.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/optional.js -//#region src/messages/index.ts -var messages_exports = {}; -__export(messages_exports, { - AIMessage: () => AIMessage, - AIMessageChunk: () => AIMessageChunk, - BaseMessage: () => BaseMessage, - BaseMessageChunk: () => BaseMessageChunk, - ChatMessage: () => ChatMessage, - ChatMessageChunk: () => ChatMessageChunk, - FunctionMessage: () => FunctionMessage, - FunctionMessageChunk: () => FunctionMessageChunk, - HumanMessage: () => HumanMessage, - HumanMessageChunk: () => HumanMessageChunk, - KNOWN_BLOCK_TYPES: () => KNOWN_BLOCK_TYPES$2, - RemoveMessage: () => RemoveMessage, - SystemMessage: () => SystemMessage, - SystemMessageChunk: () => SystemMessageChunk, - ToolMessage: () => ToolMessage, - ToolMessageChunk: () => ToolMessageChunk, - _isMessageFieldWithRole: () => _isMessageFieldWithRole, - _mergeDicts: () => _mergeDicts, - _mergeLists: () => _mergeLists, - _mergeObj: () => _mergeObj, - _mergeStatus: () => _mergeStatus, - coerceMessageLikeToMessage: () => utils_coerceMessageLikeToMessage, - convertToChunk: () => convertToChunk, - convertToOpenAIImageBlock: () => convertToOpenAIImageBlock, - convertToProviderContentBlock: () => convertToProviderContentBlock, - defaultTextSplitter: () => defaultTextSplitter, - defaultToolCallParser: () => defaultToolCallParser, - filterMessages: () => filterMessages, - getBufferString: () => getBufferString, - iife: () => utils_iife, - isAIMessage: () => isAIMessage, - isAIMessageChunk: () => isAIMessageChunk, - isBase64ContentBlock: () => isBase64ContentBlock, - isBaseMessage: () => isBaseMessage, - isBaseMessageChunk: () => isBaseMessageChunk, - isChatMessage: () => isChatMessage, - isChatMessageChunk: () => isChatMessageChunk, - isDataContentBlock: () => isDataContentBlock, - isDirectToolOutput: () => isDirectToolOutput, - isFunctionMessage: () => isFunctionMessage, - isFunctionMessageChunk: () => isFunctionMessageChunk, - isHumanMessage: () => isHumanMessage, - isHumanMessageChunk: () => isHumanMessageChunk, - isIDContentBlock: () => isIDContentBlock, - isMessage: () => isMessage, - isOpenAIToolCallArray: () => isOpenAIToolCallArray, - isPlainTextContentBlock: () => isPlainTextContentBlock, - isSystemMessage: () => isSystemMessage, - isSystemMessageChunk: () => isSystemMessageChunk, - isToolMessage: () => isToolMessage, - isToolMessageChunk: () => isToolMessageChunk, - isURLContentBlock: () => isURLContentBlock, - mapChatMessagesToStoredMessages: () => mapChatMessagesToStoredMessages, - mapStoredMessageToChatMessage: () => mapStoredMessageToChatMessage, - mapStoredMessagesToChatMessages: () => mapStoredMessagesToChatMessages, - mergeContent: () => mergeContent, - mergeMessageRuns: () => mergeMessageRuns, - mergeResponseMetadata: () => mergeResponseMetadata, - mergeUsageMetadata: () => mergeUsageMetadata, - parseBase64DataUrl: () => parseBase64DataUrl, - parseMimeType: () => parseMimeType, - trimMessages: () => trimMessages -}); +//#region src/utils/zod-to-json-schema/parsers/optional.ts +const parseOptionalDef = (def, refs) => { + if (refs.currentPath.toString() === refs.propertyPath?.toString()) return parseDef(def.innerType._def, refs); + const innerSchema = parseDef(def.innerType._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "anyOf", + "1" + ] + }); + return innerSchema ? { anyOf: [{ not: parseAnyDef(refs) }, innerSchema] } : parseAnyDef(refs); +}; //#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/chat_history.js +//# sourceMappingURL=optional.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/pipeline.js +//#region src/utils/zod-to-json-schema/parsers/pipeline.ts +const parsePipelineDef = (def, refs) => { + if (refs.pipeStrategy === "input") return parseDef(def.in._def, refs); + else if (refs.pipeStrategy === "output") return parseDef(def.out._def, refs); + const a = parseDef(def.in._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "allOf", + "0" + ] + }); + const b = parseDef(def.out._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "allOf", + a ? "1" : "0" + ] + }); + return { allOf: [a, b].filter((x) => x !== void 0) }; +}; +//#endregion +//# sourceMappingURL=pipeline.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/promise.js -//#region src/chat_history.ts -var chat_history_exports = {}; -__export(chat_history_exports, { - BaseChatMessageHistory: () => BaseChatMessageHistory, - BaseListChatMessageHistory: () => BaseListChatMessageHistory, - InMemoryChatMessageHistory: () => InMemoryChatMessageHistory -}); -/** -* Base class for all chat message histories. All chat message histories -* should extend this class. -*/ -var BaseChatMessageHistory = class extends Serializable { - /** - * Add a list of messages. - * - * Implementations should override this method to handle bulk addition of messages - * in an efficient manner to avoid unnecessary round-trips to the underlying store. - * - * @param messages - A list of BaseMessage objects to store. - */ - async addMessages(messages) { - for (const message of messages) await this.addMessage(message); - } -}; -/** -* Base class for all list chat message histories. All list chat message -* histories should extend this class. -*/ -var BaseListChatMessageHistory = class extends Serializable { - /** - * This is a convenience method for adding a human message string to the store. - * Please note that this is a convenience method. Code should favor the - * bulk addMessages interface instead to save on round-trips to the underlying - * persistence layer. - * This method may be deprecated in a future release. - */ - addUserMessage(message) { - return this.addMessage(new HumanMessage(message)); - } - /** - * This is a convenience method for adding an AI message string to the store. - * Please note that this is a convenience method. Code should favor the bulk - * addMessages interface instead to save on round-trips to the underlying - * persistence layer. - * This method may be deprecated in a future release. - */ - addAIMessage(message) { - return this.addMessage(new AIMessage(message)); - } - /** - * Add a list of messages. - * - * Implementations should override this method to handle bulk addition of messages - * in an efficient manner to avoid unnecessary round-trips to the underlying store. - * - * @param messages - A list of BaseMessage objects to store. - */ - async addMessages(messages) { - for (const message of messages) await this.addMessage(message); - } - /** - * Remove all messages from the store. - */ - clear() { - throw new Error("Not implemented."); - } -}; -/** -* Class for storing chat message history in-memory. It extends the -* BaseListChatMessageHistory class and provides methods to get, add, and -* clear messages. -*/ -var InMemoryChatMessageHistory = class extends BaseListChatMessageHistory { - lc_namespace = [ - "langchain", - "stores", - "message", - "in_memory" - ]; - messages = []; - constructor(messages) { - super(...arguments); - this.messages = messages ?? []; - } - /** - * Method to get all the messages stored in the ChatMessageHistory - * instance. - * @returns Array of stored BaseMessage instances. - */ - async getMessages() { - return this.messages; - } - /** - * Method to add a new message to the ChatMessageHistory instance. - * @param message The BaseMessage instance to add. - * @returns A promise that resolves when the message has been added. - */ - async addMessage(message) { - this.messages.push(message); - } - /** - * Method to clear all the messages from the ChatMessageHistory instance. - * @returns A promise that resolves when all messages have been cleared. - */ - async clear() { - this.messages = []; - } -}; +//#region src/utils/zod-to-json-schema/parsers/promise.ts +function parsePromiseDef(def, refs) { + return parseDef(def.type._def, refs); +} //#endregion -//# sourceMappingURL=chat_history.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/embeddings.js - - +//# sourceMappingURL=promise.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/set.js -//#region src/embeddings.ts -var embeddings_exports = {}; -__export(embeddings_exports, { Embeddings: () => Embeddings }); -/** -* An abstract class that provides methods for embedding documents and -* queries using LangChain. -*/ -var Embeddings = class { - /** - * The async caller should be used by subclasses to make any async calls, - * which will thus benefit from the concurrency and retry logic. - */ - caller; - constructor(params) { - this.caller = new async_caller_AsyncCaller(params ?? {}); - } -}; -//#endregion -//# sourceMappingURL=embeddings.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/index.js -//#region src/index.ts -var src_exports = {}; +//#region src/utils/zod-to-json-schema/parsers/set.ts +function parseSetDef(def, refs) { + const items = parseDef(def.valueType._def, { + ...refs, + currentPath: [...refs.currentPath, "items"] + }); + const schema = { + type: "array", + uniqueItems: true, + items + }; + if (def.minSize) setResponseValueAndErrors(schema, "minItems", def.minSize.value, def.minSize.message, refs); + if (def.maxSize) setResponseValueAndErrors(schema, "maxItems", def.maxSize.value, def.maxSize.message, refs); + return schema; +} //#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/memory.js +//# sourceMappingURL=set.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/tuple.js -//#region src/memory.ts -var memory_exports = {}; -__export(memory_exports, { - BaseMemory: () => BaseMemory, - getInputValue: () => getInputValue, - getOutputValue: () => getOutputValue, - getPromptInputKey: () => getPromptInputKey -}); -/** -* Abstract base class for memory in LangChain's Chains. Memory refers to -* the state in Chains. It can be used to store information about past -* executions of a Chain and inject that information into the inputs of -* future executions of the Chain. -*/ -var BaseMemory = class {}; -const getValue = (values, key) => { - if (key !== void 0) return values[key]; - const keys = Object.keys(values); - if (keys.length === 1) return values[keys[0]]; -}; -/** -* This function is used by memory classes to select the input value -* to use for the memory. If there is only one input value, it is used. -* If there are multiple input values, the inputKey must be specified. -*/ -const getInputValue = (inputValues, inputKey) => { - const value = getValue(inputValues, inputKey); - if (!value) { - const keys = Object.keys(inputValues); - throw new Error(`input values have ${keys.length} keys, you must specify an input key or pass only 1 key as input`); - } - return value; -}; -/** -* This function is used by memory classes to select the output value -* to use for the memory. If there is only one output value, it is used. -* If there are multiple output values, the outputKey must be specified. -* If no outputKey is specified, an error is thrown. -*/ -const getOutputValue = (outputValues, outputKey) => { - const value = getValue(outputValues, outputKey); - if (!value && value !== "") { - const keys = Object.keys(outputValues); - throw new Error(`output values have ${keys.length} keys, you must specify an output key or pass only 1 key as output`); - } - return value; -}; -/** -* Function used by memory classes to get the key of the prompt input, -* excluding any keys that are memory variables or the "stop" key. If -* there is not exactly one prompt input key, an error is thrown. -*/ -function getPromptInputKey(inputs, memoryVariables) { - const promptInputKeys = Object.keys(inputs).filter((key) => !memoryVariables.includes(key) && key !== "stop"); - if (promptInputKeys.length !== 1) throw new Error(`One input key expected, but got ${promptInputKeys.length}`); - return promptInputKeys[0]; +//#region src/utils/zod-to-json-schema/parsers/tuple.ts +function parseTupleDef(def, refs) { + if (def.rest) return { + type: "array", + minItems: def.items.length, + items: def.items.map((x, i) => parseDef(x._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "items", + `${i}` + ] + })).reduce((acc, x) => x === void 0 ? acc : [...acc, x], []), + additionalItems: parseDef(def.rest._def, { + ...refs, + currentPath: [...refs.currentPath, "additionalItems"] + }) + }; + else return { + type: "array", + minItems: def.items.length, + maxItems: def.items.length, + items: def.items.map((x, i) => parseDef(x._def, { + ...refs, + currentPath: [ + ...refs.currentPath, + "items", + `${i}` + ] + })).reduce((acc, x) => x === void 0 ? acc : [...acc, x], []) + }; } //#endregion -//# sourceMappingURL=memory.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompt_values.js +//# sourceMappingURL=tuple.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/undefined.js +//#region src/utils/zod-to-json-schema/parsers/undefined.ts +function parseUndefinedDef(refs) { + return { not: parseAnyDef(refs) }; +} +//#endregion +//# sourceMappingURL=undefined.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/unknown.js -//#region src/prompt_values.ts -var prompt_values_exports = {}; -__export(prompt_values_exports, { - BasePromptValue: () => BasePromptValue, - ChatPromptValue: () => ChatPromptValue, - ImagePromptValue: () => ImagePromptValue, - StringPromptValue: () => StringPromptValue -}); -/** -* Base PromptValue class. All prompt values should extend this class. -*/ -var BasePromptValue = class extends Serializable {}; -/** -* Represents a prompt value as a string. It extends the BasePromptValue -* class and overrides the toString and toChatMessages methods. -*/ -var StringPromptValue = class extends BasePromptValue { - static lc_name() { - return "StringPromptValue"; - } - lc_namespace = ["langchain_core", "prompt_values"]; - lc_serializable = true; - value; - constructor(value) { - super({ value }); - this.value = value; - } - toString() { - return this.value; - } - toChatMessages() { - return [new HumanMessage(this.value)]; - } -}; -/** -* Class that represents a chat prompt value. It extends the -* BasePromptValue and includes an array of BaseMessage instances. -*/ -var ChatPromptValue = class extends BasePromptValue { - lc_namespace = ["langchain_core", "prompt_values"]; - lc_serializable = true; - static lc_name() { - return "ChatPromptValue"; - } - messages; - constructor(fields) { - if (Array.isArray(fields)) fields = { messages: fields }; - super(fields); - this.messages = fields.messages; - } - toString() { - return getBufferString(this.messages); - } - toChatMessages() { - return this.messages; - } -}; -/** -* Class that represents an image prompt value. It extends the -* BasePromptValue and includes an ImageURL instance. -*/ -var ImagePromptValue = class extends BasePromptValue { - lc_namespace = ["langchain_core", "prompt_values"]; - lc_serializable = true; - static lc_name() { - return "ImagePromptValue"; - } - imageUrl; - /** @ignore */ - value; - constructor(fields) { - if (!("imageUrl" in fields)) fields = { imageUrl: fields }; - super(fields); - this.imageUrl = fields.imageUrl; - } - toString() { - return this.imageUrl.url; - } - toChatMessages() { - return [new HumanMessage({ content: [{ - type: "image_url", - image_url: { - detail: this.imageUrl.detail, - url: this.imageUrl.url - } - }] })]; - } -}; -//#endregion +//#region src/utils/zod-to-json-schema/parsers/unknown.ts +function parseUnknownDef(refs) { + return parseAnyDef(refs); +} -//# sourceMappingURL=prompt_values.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/stores.js +//#endregion +//# sourceMappingURL=unknown.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parsers/readonly.js -//#region src/stores.ts -var stores_exports = {}; -__export(stores_exports, { - BaseStore: () => BaseStore, - InMemoryStore: () => InMemoryStore -}); -/** -* Abstract interface for a key-value store. -*/ -var BaseStore = class extends Serializable {}; -/** -* In-memory implementation of the BaseStore using a dictionary. Used for -* storing key-value pairs in memory. -* @example -* ```typescript -* const store = new InMemoryStore(); -* await store.mset( -* Array.from({ length: 5 }).map((_, index) => [ -* `message:id:${index}`, -* index % 2 === 0 -* ? new AIMessage("ai stuff...") -* : new HumanMessage("human stuff..."), -* ]), -* ); -* -* const retrievedMessages = await store.mget(["message:id:0", "message:id:1"]); -* await store.mdelete(await store.yieldKeys("message:id:").toArray()); -* ``` -*/ -var InMemoryStore = class extends BaseStore { - lc_namespace = ["langchain", "storage"]; - store = {}; - /** - * Retrieves the values associated with the given keys from the store. - * @param keys Keys to retrieve values for. - * @returns Array of values associated with the given keys. - */ - async mget(keys) { - return keys.map((key) => this.store[key]); - } - /** - * Sets the values for the given keys in the store. - * @param keyValuePairs Array of key-value pairs to set in the store. - * @returns Promise that resolves when all key-value pairs have been set. - */ - async mset(keyValuePairs) { - for (const [key, value] of keyValuePairs) this.store[key] = value; - } - /** - * Deletes the given keys and their associated values from the store. - * @param keys Keys to delete from the store. - * @returns Promise that resolves when all keys have been deleted. - */ - async mdelete(keys) { - for (const key of keys) delete this.store[key]; - } - /** - * Asynchronous generator that yields keys from the store. If a prefix is - * provided, it only yields keys that start with the prefix. - * @param prefix Optional prefix to filter keys. - * @returns AsyncGenerator that yields keys from the store. - */ - async *yieldKeys(prefix) { - const keys = Object.keys(this.store); - for (const key of keys) if (prefix === void 0 || key.startsWith(prefix)) yield key; - } +//#region src/utils/zod-to-json-schema/parsers/readonly.ts +const parseReadonlyDef = (def, refs) => { + return parseDef(def.innerType._def, refs); }; //#endregion -//# sourceMappingURL=stores.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/retrievers/index.js +//# sourceMappingURL=readonly.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/selectParser.js -//#region src/retrievers/index.ts -var retrievers_exports = {}; -__export(retrievers_exports, { BaseRetriever: () => BaseRetriever }); -/** -* Abstract base class for a document retrieval system, designed to -* process string queries and return the most relevant documents from a source. -* -* `BaseRetriever` provides common properties and methods for derived retrievers, -* such as callbacks, tagging, and verbose logging. Custom retrieval systems -* should extend this class and implement `_getRelevantDocuments` to define -* the specific retrieval logic. -* -* @template Metadata - The type of metadata associated with each document, -* defaulting to `Record`. -*/ -var BaseRetriever = class extends Runnable { - /** - * Optional callbacks to handle various events in the retrieval process. - */ - callbacks; - /** - * Tags to label or categorize the retrieval operation. - */ - tags; - /** - * Metadata to provide additional context or information about the retrieval - * operation. - */ - metadata; - /** - * If set to `true`, enables verbose logging for the retrieval process. - */ - verbose; - /** - * Constructs a new `BaseRetriever` instance with optional configuration fields. - * - * @param fields - Optional input configuration that can include `callbacks`, - * `tags`, `metadata`, and `verbose` settings for custom retriever behavior. - */ - constructor(fields) { - super(fields); - this.callbacks = fields?.callbacks; - this.tags = fields?.tags ?? []; - this.metadata = fields?.metadata ?? {}; - this.verbose = fields?.verbose ?? false; - } - /** - * TODO: This should be an abstract method, but we'd like to avoid breaking - * changes to people currently using subclassed custom retrievers. - * Change it on next major release. - */ - /** - * Placeholder method for retrieving relevant documents based on a query. - * - * This method is intended to be implemented by subclasses and will be - * converted to an abstract method in the next major release. Currently, it - * throws an error if not implemented, ensuring that custom retrievers define - * the specific retrieval logic. - * - * @param _query - The query string used to search for relevant documents. - * @param _callbacks - (optional) Callback manager for managing callbacks - * during retrieval. - * @returns A promise resolving to an array of `DocumentInterface` instances relevant to the query. - * @throws {Error} Throws an error indicating the method is not implemented. - */ - _getRelevantDocuments(_query, _callbacks) { - throw new Error("Not implemented!"); - } - /** - * Executes a retrieval operation. - * - * @param input - The query string used to search for relevant documents. - * @param options - (optional) Configuration options for the retrieval run, - * which may include callbacks, tags, and metadata. - * @returns A promise that resolves to an array of `DocumentInterface` instances - * representing the most relevant documents to the query. - */ - async invoke(input, options) { - const parsedConfig = ensureConfig(parseCallbackConfigArg(options)); - const callbackManager_ = await CallbackManager.configure(parsedConfig.callbacks, this.callbacks, parsedConfig.tags, this.tags, parsedConfig.metadata, this.metadata, { verbose: this.verbose }); - const runManager = await callbackManager_?.handleRetrieverStart(this.toJSON(), input, parsedConfig.runId, void 0, void 0, void 0, parsedConfig.runName); - try { - const results = await this._getRelevantDocuments(input, runManager); - await runManager?.handleRetrieverEnd(results); - return results; - } catch (error) { - await runManager?.handleRetrieverError(error); - throw error; - } - } -}; -//#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/vectorstores.js -//#region src/vectorstores.ts -var vectorstores_exports = {}; -__export(vectorstores_exports, { - SaveableVectorStore: () => SaveableVectorStore, - VectorStore: () => VectorStore, - VectorStoreRetriever: () => VectorStoreRetriever -}); -/** -* Class for retrieving documents from a `VectorStore` based on vector similarity -* or maximal marginal relevance (MMR). -* -* `VectorStoreRetriever` extends `BaseRetriever`, implementing methods for -* adding documents to the underlying vector store and performing document -* retrieval with optional configurations. -* -* @class VectorStoreRetriever -* @extends BaseRetriever -* @implements VectorStoreRetrieverInterface -* @template V - Type of vector store implementing `VectorStoreInterface`. -*/ -var VectorStoreRetriever = class extends BaseRetriever { - static lc_name() { - return "VectorStoreRetriever"; - } - get lc_namespace() { - return ["langchain_core", "vectorstores"]; - } - /** - * The instance of `VectorStore` used for storing and retrieving document embeddings. - * This vector store must implement the `VectorStoreInterface` to be compatible - * with the retriever’s operations. - */ - vectorStore; - /** - * Specifies the number of documents to retrieve for each search query. - * Defaults to 4 if not specified, providing a basic result count for similarity or MMR searches. - */ - k = 4; - /** - * Determines the type of search operation to perform on the vector store. - * - * - `"similarity"` (default): Conducts a similarity search based purely on vector similarity - * to the query. - * - `"mmr"`: Executes a maximal marginal relevance (MMR) search, balancing relevance and - * diversity in the retrieved results. - */ - searchType = "similarity"; - /** - * Additional options specific to maximal marginal relevance (MMR) search, applicable - * only if `searchType` is set to `"mmr"`. - * - * Includes: - * - `fetchK`: The initial number of documents fetched before applying the MMR algorithm, - * allowing for a larger selection from which to choose the most diverse results. - * - `lambda`: A parameter between 0 and 1 to adjust the relevance-diversity balance, - * where 0 prioritizes diversity and 1 prioritizes relevance. - */ - searchKwargs; - /** - * Optional filter applied to search results, defined by the `FilterType` of the vector store. - * Allows for refined, targeted results by restricting the returned documents based - * on specified filter criteria. - */ - filter; - /** - * Returns the type of vector store, as defined by the `vectorStore` instance. - * - * @returns {string} The vector store type. - */ - _vectorstoreType() { - return this.vectorStore._vectorstoreType(); - } - /** - * Initializes a new instance of `VectorStoreRetriever` with the specified configuration. - * - * This constructor configures the retriever to interact with a given `VectorStore` - * and supports different retrieval strategies, including similarity search and maximal - * marginal relevance (MMR) search. Various options allow customization of the number - * of documents retrieved per query, filtering based on conditions, and fine-tuning - * MMR-specific parameters. - * - * @param fields - Configuration options for setting up the retriever: - * - * - `vectorStore` (required): The `VectorStore` instance implementing `VectorStoreInterface` - * that will be used to store and retrieve document embeddings. This is the core component - * of the retriever, enabling vector-based similarity and MMR searches. - * - * - `k` (optional): Specifies the number of documents to retrieve per search query. If not - * provided, defaults to 4. This count determines the number of most relevant documents returned - * for each search operation, balancing performance with comprehensiveness. - * - * - `searchType` (optional): Defines the search approach used by the retriever, allowing for - * flexibility between two methods: - * - `"similarity"` (default): A similarity-based search, retrieving documents with high vector - * similarity to the query. This type prioritizes relevance and is often used when diversity - * among results is less critical. - * - `"mmr"`: Maximal Marginal Relevance search, which combines relevance with diversity. MMR - * is useful for scenarios where varied content is essential, as it selects results that - * both match the query and introduce content diversity. - * - * - `filter` (optional): A filter of type `FilterType`, defined by the vector store, that allows - * for refined and targeted search results. This filter applies specified conditions to limit - * which documents are eligible for retrieval, offering control over the scope of results. - * - * - `searchKwargs` (optional, applicable only if `searchType` is `"mmr"`): Additional settings - * for configuring MMR-specific behavior. These parameters allow further tuning of the MMR - * search process: - * - `fetchK`: The initial number of documents fetched from the vector store before the MMR - * algorithm is applied. Fetching a larger set enables the algorithm to select a more - * diverse subset of documents. - * - `lambda`: A parameter controlling the relevance-diversity balance, where 0 emphasizes - * diversity and 1 prioritizes relevance. Intermediate values provide a blend of the two, - * allowing customization based on the importance of content variety relative to query relevance. - */ - constructor(fields) { - super(fields); - this.vectorStore = fields.vectorStore; - this.k = fields.k ?? this.k; - this.searchType = fields.searchType ?? this.searchType; - this.filter = fields.filter; - if (fields.searchType === "mmr") this.searchKwargs = fields.searchKwargs; - } - /** - * Retrieves relevant documents based on the specified query, using either - * similarity or maximal marginal relevance (MMR) search. - * - * If `searchType` is set to `"mmr"`, performs an MMR search to balance - * similarity and diversity among results. If `searchType` is `"similarity"`, - * retrieves results purely based on similarity to the query. - * - * @param query - The query string used to find relevant documents. - * @param runManager - Optional callback manager for tracking retrieval progress. - * @returns A promise that resolves to an array of `DocumentInterface` instances - * representing the most relevant documents to the query. - * @throws {Error} Throws an error if MMR search is requested but not supported - * by the vector store. - * @protected - */ - async _getRelevantDocuments(query, runManager) { - if (this.searchType === "mmr") { - if (typeof this.vectorStore.maxMarginalRelevanceSearch !== "function") throw new Error(`The vector store backing this retriever, ${this._vectorstoreType()} does not support max marginal relevance search.`); - return this.vectorStore.maxMarginalRelevanceSearch(query, { - k: this.k, - filter: this.filter, - ...this.searchKwargs - }, runManager?.getChild("vectorstore")); - } - return this.vectorStore.similaritySearch(query, this.k, this.filter, runManager?.getChild("vectorstore")); - } - /** - * Adds an array of documents to the vector store, embedding them as part of - * the storage process. - * - * This method delegates document embedding and storage to the `addDocuments` - * method of the underlying vector store. - * - * @param documents - An array of documents to embed and add to the vector store. - * @param options - Optional settings to customize document addition. - * @returns A promise that resolves to an array of document IDs or `void`, - * depending on the vector store's implementation. - */ - async addDocuments(documents, options) { - return this.vectorStore.addDocuments(documents, options); + + + + + + + + + + + + + + + + + + + + + +//#region src/utils/zod-to-json-schema/selectParser.ts +const selectParser = (def, typeName, refs) => { + switch (typeName) { + case ZodFirstPartyTypeKind.ZodString: return parseStringDef(def, refs); + case ZodFirstPartyTypeKind.ZodNumber: return parseNumberDef(def, refs); + case ZodFirstPartyTypeKind.ZodObject: return parseObjectDef(def, refs); + case ZodFirstPartyTypeKind.ZodBigInt: return parseBigintDef(def, refs); + case ZodFirstPartyTypeKind.ZodBoolean: return parseBooleanDef(); + case ZodFirstPartyTypeKind.ZodDate: return parseDateDef(def, refs); + case ZodFirstPartyTypeKind.ZodUndefined: return parseUndefinedDef(refs); + case ZodFirstPartyTypeKind.ZodNull: return parseNullDef(refs); + case ZodFirstPartyTypeKind.ZodArray: return parseArrayDef(def, refs); + case ZodFirstPartyTypeKind.ZodUnion: + case ZodFirstPartyTypeKind.ZodDiscriminatedUnion: return parseUnionDef(def, refs); + case ZodFirstPartyTypeKind.ZodIntersection: return parseIntersectionDef(def, refs); + case ZodFirstPartyTypeKind.ZodTuple: return parseTupleDef(def, refs); + case ZodFirstPartyTypeKind.ZodRecord: return parseRecordDef(def, refs); + case ZodFirstPartyTypeKind.ZodLiteral: return parseLiteralDef(def, refs); + case ZodFirstPartyTypeKind.ZodEnum: return parseEnumDef(def); + case ZodFirstPartyTypeKind.ZodNativeEnum: return parseNativeEnumDef(def); + case ZodFirstPartyTypeKind.ZodNullable: return parseNullableDef(def, refs); + case ZodFirstPartyTypeKind.ZodOptional: return parseOptionalDef(def, refs); + case ZodFirstPartyTypeKind.ZodMap: return parseMapDef(def, refs); + case ZodFirstPartyTypeKind.ZodSet: return parseSetDef(def, refs); + case ZodFirstPartyTypeKind.ZodLazy: return () => def.getter()._def; + case ZodFirstPartyTypeKind.ZodPromise: return parsePromiseDef(def, refs); + case ZodFirstPartyTypeKind.ZodNaN: + case ZodFirstPartyTypeKind.ZodNever: return parseNeverDef(refs); + case ZodFirstPartyTypeKind.ZodEffects: return parseEffectsDef(def, refs); + case ZodFirstPartyTypeKind.ZodAny: return parseAnyDef(refs); + case ZodFirstPartyTypeKind.ZodUnknown: return parseUnknownDef(refs); + case ZodFirstPartyTypeKind.ZodDefault: return parseDefaultDef(def, refs); + case ZodFirstPartyTypeKind.ZodBranded: return parseBrandedDef(def, refs); + case ZodFirstPartyTypeKind.ZodReadonly: return parseReadonlyDef(def, refs); + case ZodFirstPartyTypeKind.ZodCatch: return parseCatchDef(def, refs); + case ZodFirstPartyTypeKind.ZodPipeline: return parsePipelineDef(def, refs); + case ZodFirstPartyTypeKind.ZodFunction: + case ZodFirstPartyTypeKind.ZodVoid: + case ZodFirstPartyTypeKind.ZodSymbol: return void 0; + default: + /* c8 ignore next */ + return ((_) => void 0)(typeName); } }; -/** -* Abstract class representing a vector storage system for performing -* similarity searches on embedded documents. -* -* `VectorStore` provides methods for adding precomputed vectors or documents, -* removing documents based on criteria, and performing similarity searches -* with optional scoring. Subclasses are responsible for implementing specific -* storage mechanisms and the exact behavior of certain abstract methods. -* -* @abstract -* @extends Serializable -* @implements VectorStoreInterface -*/ -var VectorStore = class extends Serializable { - /** - * Namespace within LangChain to uniquely identify this vector store's - * location, based on the vector store type. - * - * @internal - */ - lc_namespace = [ - "langchain", - "vectorstores", - this._vectorstoreType() - ]; - /** - * Embeddings interface for generating vector embeddings from text queries, - * enabling vector-based similarity searches. - */ - embeddings; - /** - * Initializes a new vector store with embeddings and database configuration. - * - * @param embeddings - Instance of `EmbeddingsInterface` used to embed queries. - * @param dbConfig - Configuration settings for the database or storage system. - */ - constructor(embeddings, dbConfig) { - super(dbConfig); - this.embeddings = embeddings; - } - /** - * Deletes documents from the vector store based on the specified parameters. - * - * @param _params - Flexible key-value pairs defining conditions for document deletion. - * @returns A promise that resolves once the deletion is complete. - */ - async delete(_params) { - throw new Error("Not implemented."); - } - /** - * Searches for documents similar to a text query by embedding the query and - * performing a similarity search on the resulting vector. - * - * @param query - Text query for finding similar documents. - * @param k - Number of similar results to return. Defaults to 4. - * @param filter - Optional filter based on `FilterType`. - * @param _callbacks - Optional callbacks for monitoring search progress - * @returns A promise resolving to an array of `DocumentInterface` instances representing similar documents. - */ - async similaritySearch(query, k = 4, filter = void 0, _callbacks = void 0) { - const results = await this.similaritySearchVectorWithScore(await this.embeddings.embedQuery(query), k, filter); - return results.map((result) => result[0]); + +//#endregion + +//# sourceMappingURL=selectParser.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/parseDef.js + + + + + +//#region src/utils/zod-to-json-schema/parseDef.ts +function parseDef(def, refs, forceResolution = false) { + const seenItem = refs.seen.get(def); + if (refs.override) { + const overrideResult = refs.override?.(def, refs, seenItem, forceResolution); + if (overrideResult !== ignoreOverride) return overrideResult; } - /** - * Searches for documents similar to a text query by embedding the query, - * and returns results with similarity scores. - * - * @param query - Text query for finding similar documents. - * @param k - Number of similar results to return. Defaults to 4. - * @param filter - Optional filter based on `FilterType`. - * @param _callbacks - Optional callbacks for monitoring search progress - * @returns A promise resolving to an array of tuples, each containing a - * document and its similarity score. - */ - async similaritySearchWithScore(query, k = 4, filter = void 0, _callbacks = void 0) { - return this.similaritySearchVectorWithScore(await this.embeddings.embedQuery(query), k, filter); + if (seenItem && !forceResolution) { + const seenSchema = get$ref(seenItem, refs); + if (seenSchema !== void 0) return seenSchema; } - /** - * Creates a `VectorStore` instance from an array of text strings and optional - * metadata, using the specified embeddings and database configuration. - * - * Subclasses must implement this method to define how text and metadata - * are embedded and stored in the vector store. Throws an error if not overridden. - * - * @param _texts - Array of strings representing the text documents to be stored. - * @param _metadatas - Metadata for the texts, either as an array (one for each text) - * or a single object (applied to all texts). - * @param _embeddings - Instance of `EmbeddingsInterface` to embed the texts. - * @param _dbConfig - Database configuration settings. - * @returns A promise that resolves to a new `VectorStore` instance. - * @throws {Error} Throws an error if this method is not overridden by a subclass. - */ - static fromTexts(_texts, _metadatas, _embeddings, _dbConfig) { - throw new Error("the Langchain vectorstore implementation you are using forgot to override this, please report a bug"); + const newItem = { + def, + path: refs.currentPath, + jsonSchema: void 0 + }; + refs.seen.set(def, newItem); + const jsonSchemaOrGetter = selectParser(def, def.typeName, refs); + const jsonSchema = typeof jsonSchemaOrGetter === "function" ? parseDef(jsonSchemaOrGetter(), refs) : jsonSchemaOrGetter; + if (jsonSchema) addMeta(def, refs, jsonSchema); + if (refs.postProcess) { + const postProcessResult = refs.postProcess(jsonSchema, def, refs); + newItem.jsonSchema = jsonSchema; + return postProcessResult; } - /** - * Creates a `VectorStore` instance from an array of documents, using the specified - * embeddings and database configuration. - * - * Subclasses must implement this method to define how documents are embedded - * and stored. Throws an error if not overridden. - * - * @param _docs - Array of `DocumentInterface` instances representing the documents to be stored. - * @param _embeddings - Instance of `EmbeddingsInterface` to embed the documents. - * @param _dbConfig - Database configuration settings. - * @returns A promise that resolves to a new `VectorStore` instance. - * @throws {Error} Throws an error if this method is not overridden by a subclass. - */ - static fromDocuments(_docs, _embeddings, _dbConfig) { - throw new Error("the Langchain vectorstore implementation you are using forgot to override this, please report a bug"); + newItem.jsonSchema = jsonSchema; + return jsonSchema; +} +const get$ref = (item, refs) => { + switch (refs.$refStrategy) { + case "root": return { $ref: item.path.join("/") }; + case "relative": return { $ref: getRelativePath(refs.currentPath, item.path) }; + case "none": + case "seen": + if (item.path.length < refs.currentPath.length && item.path.every((value, index) => refs.currentPath[index] === value)) { + console.warn(`Recursive reference detected at ${refs.currentPath.join("/")}! Defaulting to any`); + return parseAnyDef(refs); + } + return refs.$refStrategy === "seen" ? parseAnyDef(refs) : void 0; } - /** - * Creates a `VectorStoreRetriever` instance with flexible configuration options. - * - * @param kOrFields - * - If a number is provided, it sets the `k` parameter (number of items to retrieve). - * - If an object is provided, it should contain various configuration options. - * @param filter - * - Optional filter criteria to limit the items retrieved based on the specified filter type. - * @param callbacks - * - Optional callbacks that may be triggered at specific stages of the retrieval process. - * @param tags - * - Tags to categorize or label the `VectorStoreRetriever`. Defaults to an empty array if not provided. - * @param metadata - * - Additional metadata as key-value pairs to add contextual information for the retrieval process. - * @param verbose - * - If `true`, enables detailed logging for the retrieval process. Defaults to `false`. - * - * @returns - * - A configured `VectorStoreRetriever` instance based on the provided parameters. - * - * @example - * Basic usage with a `k` value: - * ```typescript - * const retriever = myVectorStore.asRetriever(5); - * ``` - * - * Usage with a configuration object: - * ```typescript - * const retriever = myVectorStore.asRetriever({ - * k: 10, - * filter: myFilter, - * tags: ['example', 'test'], - * verbose: true, - * searchType: 'mmr', - * searchKwargs: { alpha: 0.5 }, - * }); - * ``` - */ - asRetriever(kOrFields, filter, callbacks, tags, metadata, verbose) { - if (typeof kOrFields === "number") return new VectorStoreRetriever({ - vectorStore: this, - k: kOrFields, - filter, - tags: [...tags ?? [], this._vectorstoreType()], - metadata, - verbose, - callbacks - }); - else { - const params = { - vectorStore: this, - k: kOrFields?.k, - filter: kOrFields?.filter, - tags: [...kOrFields?.tags ?? [], this._vectorstoreType()], - metadata: kOrFields?.metadata, - verbose: kOrFields?.verbose, - callbacks: kOrFields?.callbacks, - searchType: kOrFields?.searchType - }; - if (kOrFields?.searchType === "mmr") return new VectorStoreRetriever({ - ...params, - searchKwargs: kOrFields.searchKwargs - }); - return new VectorStoreRetriever({ ...params }); - } +}; +const addMeta = (def, refs, jsonSchema) => { + if (def.description) { + jsonSchema.description = def.description; + if (refs.markdownDescription) jsonSchema.markdownDescription = def.description; } + return jsonSchema; }; -/** -* Abstract class extending `VectorStore` that defines a contract for saving -* and loading vector store instances. -* -* The `SaveableVectorStore` class allows vector store implementations to -* persist their data and retrieve it when needed.The format for saving and -* loading data is left to the implementing subclass. -* -* Subclasses must implement the `save` method to handle their custom -* serialization logic, while the `load` method enables reconstruction of a -* vector store from saved data, requiring compatible embeddings through the -* `EmbeddingsInterface`. -* -* @abstract -* @extends VectorStore -*/ -var SaveableVectorStore = class extends VectorStore { - /** - * Loads a vector store instance from the specified directory, using the - * provided embeddings to ensure compatibility. - * - * This static method reconstructs a `SaveableVectorStore` from previously - * saved data. Implementations should interpret the saved data format to - * recreate the vector store instance. - * - * @param _directory - The directory path from which the vector store - * data will be loaded. - * @param _embeddings - An instance of `EmbeddingsInterface` to align - * the embeddings with the loaded vector data. - * @returns A promise that resolves to a `SaveableVectorStore` instance - * constructed from the saved data. - */ - static load(_directory, _embeddings) { - throw new Error("Not implemented"); + +//#endregion + +//# sourceMappingURL=parseDef.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/zodToJsonSchema.js + + + + +//#region src/utils/zod-to-json-schema/zodToJsonSchema.ts +const zodToJsonSchema_zodToJsonSchema = (schema, options) => { + const refs = getRefs(options); + let definitions = typeof options === "object" && options.definitions ? Object.entries(options.definitions).reduce((acc, [name$1, schema$1]) => ({ + ...acc, + [name$1]: parseDef(schema$1._def, { + ...refs, + currentPath: [ + ...refs.basePath, + refs.definitionPath, + name$1 + ] + }, true) ?? parseAnyDef(refs) + }), {}) : void 0; + const name = typeof options === "string" ? options : options?.nameStrategy === "title" ? void 0 : options?.name; + const main = parseDef(schema._def, name === void 0 ? refs : { + ...refs, + currentPath: [ + ...refs.basePath, + refs.definitionPath, + name + ] + }, false) ?? parseAnyDef(refs); + const title = typeof options === "object" && options.name !== void 0 && options.nameStrategy === "title" ? options.name : void 0; + if (title !== void 0) main.title = title; + if (refs.flags.hasReferencedOpenAiAnyType) { + if (!definitions) definitions = {}; + if (!definitions[refs.openAiAnyTypeName]) definitions[refs.openAiAnyTypeName] = { + type: [ + "string", + "number", + "integer", + "boolean", + "array", + "null" + ], + items: { $ref: refs.$refStrategy === "relative" ? "1" : [ + ...refs.basePath, + refs.definitionPath, + refs.openAiAnyTypeName + ].join("/") } + }; } + const combined = name === void 0 ? definitions ? { + ...main, + [refs.definitionPath]: definitions + } : main : { + $ref: [ + ...refs.$refStrategy === "relative" ? [] : refs.basePath, + refs.definitionPath, + name + ].join("/"), + [refs.definitionPath]: { + ...definitions, + [name]: main + } + }; + if (refs.target === "jsonSchema7") combined.$schema = "http://json-schema.org/draft-07/schema#"; + else if (refs.target === "jsonSchema2019-09" || refs.target === "openAi") combined.$schema = "https://json-schema.org/draft/2019-09/schema#"; + if (refs.target === "openAi" && ("anyOf" in combined || "oneOf" in combined || "allOf" in combined || "type" in combined && Array.isArray(combined.type))) console.warn("Warning: OpenAI may not support schemas with unions as roots! Try wrapping it in an object property."); + return combined; }; -//#endregion +//#endregion + +//# sourceMappingURL=zodToJsonSchema.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/zod-to-json-schema/index.js + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +;// CONCATENATED MODULE: ./node_modules/zod/v4/core/to-json-schema.js + + +class JSONSchemaGenerator { + constructor(params) { + this.counter = 0; + this.metadataRegistry = params?.metadata ?? globalRegistry; + this.target = params?.target ?? "draft-2020-12"; + this.unrepresentable = params?.unrepresentable ?? "throw"; + this.override = params?.override ?? (() => { }); + this.io = params?.io ?? "output"; + this.seen = new Map(); + } + process(schema, _params = { path: [], schemaPath: [] }) { + var _a; + const def = schema._zod.def; + const formatMap = { + guid: "uuid", + url: "uri", + datetime: "date-time", + json_string: "json-string", + regex: "", // do not set + }; + // check for schema in seens + const seen = this.seen.get(schema); + if (seen) { + seen.count++; + // check if cycle + const isCycle = _params.schemaPath.includes(schema); + if (isCycle) { + seen.cycle = _params.path; + } + return seen.schema; + } + // initialize + const result = { schema: {}, count: 1, cycle: undefined, path: _params.path }; + this.seen.set(schema, result); + // custom method overrides default behavior + const overrideSchema = schema._zod.toJSONSchema?.(); + if (overrideSchema) { + result.schema = overrideSchema; + } + else { + const params = { + ..._params, + schemaPath: [..._params.schemaPath, schema], + path: _params.path, + }; + const parent = schema._zod.parent; + if (parent) { + // schema was cloned from another schema + result.ref = parent; + this.process(parent, params); + this.seen.get(parent).isParent = true; + } + else { + const _json = result.schema; + switch (def.type) { + case "string": { + const json = _json; + json.type = "string"; + const { minimum, maximum, format, patterns, contentEncoding } = schema._zod + .bag; + if (typeof minimum === "number") + json.minLength = minimum; + if (typeof maximum === "number") + json.maxLength = maximum; + // custom pattern overrides format + if (format) { + json.format = formatMap[format] ?? format; + if (json.format === "") + delete json.format; // empty format is not valid + } + if (contentEncoding) + json.contentEncoding = contentEncoding; + if (patterns && patterns.size > 0) { + const regexes = [...patterns]; + if (regexes.length === 1) + json.pattern = regexes[0].source; + else if (regexes.length > 1) { + result.schema.allOf = [ + ...regexes.map((regex) => ({ + ...(this.target === "draft-7" ? { type: "string" } : {}), + pattern: regex.source, + })), + ]; + } + } + break; + } + case "number": { + const json = _json; + const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; + if (typeof format === "string" && format.includes("int")) + json.type = "integer"; + else + json.type = "number"; + if (typeof exclusiveMinimum === "number") + json.exclusiveMinimum = exclusiveMinimum; + if (typeof minimum === "number") { + json.minimum = minimum; + if (typeof exclusiveMinimum === "number") { + if (exclusiveMinimum >= minimum) + delete json.minimum; + else + delete json.exclusiveMinimum; + } + } + if (typeof exclusiveMaximum === "number") + json.exclusiveMaximum = exclusiveMaximum; + if (typeof maximum === "number") { + json.maximum = maximum; + if (typeof exclusiveMaximum === "number") { + if (exclusiveMaximum <= maximum) + delete json.maximum; + else + delete json.exclusiveMaximum; + } + } + if (typeof multipleOf === "number") + json.multipleOf = multipleOf; + break; + } + case "boolean": { + const json = _json; + json.type = "boolean"; + break; + } + case "bigint": { + if (this.unrepresentable === "throw") { + throw new Error("BigInt cannot be represented in JSON Schema"); + } + break; + } + case "symbol": { + if (this.unrepresentable === "throw") { + throw new Error("Symbols cannot be represented in JSON Schema"); + } + break; + } + case "null": { + _json.type = "null"; + break; + } + case "any": { + break; + } + case "unknown": { + break; + } + case "undefined": { + if (this.unrepresentable === "throw") { + throw new Error("Undefined cannot be represented in JSON Schema"); + } + break; + } + case "void": { + if (this.unrepresentable === "throw") { + throw new Error("Void cannot be represented in JSON Schema"); + } + break; + } + case "never": { + _json.not = {}; + break; + } + case "date": { + if (this.unrepresentable === "throw") { + throw new Error("Date cannot be represented in JSON Schema"); + } + break; + } + case "array": { + const json = _json; + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") + json.minItems = minimum; + if (typeof maximum === "number") + json.maxItems = maximum; + json.type = "array"; + json.items = this.process(def.element, { ...params, path: [...params.path, "items"] }); + break; + } + case "object": { + const json = _json; + json.type = "object"; + json.properties = {}; + const shape = def.shape; // params.shapeCache.get(schema)!; + for (const key in shape) { + json.properties[key] = this.process(shape[key], { + ...params, + path: [...params.path, "properties", key], + }); + } + // required keys + const allKeys = new Set(Object.keys(shape)); + // const optionalKeys = new Set(def.optional); + const requiredKeys = new Set([...allKeys].filter((key) => { + const v = def.shape[key]._zod; + if (this.io === "input") { + return v.optin === undefined; + } + else { + return v.optout === undefined; + } + })); + if (requiredKeys.size > 0) { + json.required = Array.from(requiredKeys); + } + // catchall + if (def.catchall?._zod.def.type === "never") { + // strict + json.additionalProperties = false; + } + else if (!def.catchall) { + // regular + if (this.io === "output") + json.additionalProperties = false; + } + else if (def.catchall) { + json.additionalProperties = this.process(def.catchall, { + ...params, + path: [...params.path, "additionalProperties"], + }); + } + break; + } + case "union": { + const json = _json; + json.anyOf = def.options.map((x, i) => this.process(x, { + ...params, + path: [...params.path, "anyOf", i], + })); + break; + } + case "intersection": { + const json = _json; + const a = this.process(def.left, { + ...params, + path: [...params.path, "allOf", 0], + }); + const b = this.process(def.right, { + ...params, + path: [...params.path, "allOf", 1], + }); + const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1; + const allOf = [ + ...(isSimpleIntersection(a) ? a.allOf : [a]), + ...(isSimpleIntersection(b) ? b.allOf : [b]), + ]; + json.allOf = allOf; + break; + } + case "tuple": { + const json = _json; + json.type = "array"; + const prefixItems = def.items.map((x, i) => this.process(x, { ...params, path: [...params.path, "prefixItems", i] })); + if (this.target === "draft-2020-12") { + json.prefixItems = prefixItems; + } + else { + json.items = prefixItems; + } + if (def.rest) { + const rest = this.process(def.rest, { + ...params, + path: [...params.path, "items"], + }); + if (this.target === "draft-2020-12") { + json.items = rest; + } + else { + json.additionalItems = rest; + } + } + // additionalItems + if (def.rest) { + json.items = this.process(def.rest, { + ...params, + path: [...params.path, "items"], + }); + } + // length + const { minimum, maximum } = schema._zod.bag; + if (typeof minimum === "number") + json.minItems = minimum; + if (typeof maximum === "number") + json.maxItems = maximum; + break; + } + case "record": { + const json = _json; + json.type = "object"; + json.propertyNames = this.process(def.keyType, { ...params, path: [...params.path, "propertyNames"] }); + json.additionalProperties = this.process(def.valueType, { + ...params, + path: [...params.path, "additionalProperties"], + }); + break; + } + case "map": { + if (this.unrepresentable === "throw") { + throw new Error("Map cannot be represented in JSON Schema"); + } + break; + } + case "set": { + if (this.unrepresentable === "throw") { + throw new Error("Set cannot be represented in JSON Schema"); + } + break; + } + case "enum": { + const json = _json; + const values = getEnumValues(def.entries); + // Number enums can have both string and number values + if (values.every((v) => typeof v === "number")) + json.type = "number"; + if (values.every((v) => typeof v === "string")) + json.type = "string"; + json.enum = values; + break; + } + case "literal": { + const json = _json; + const vals = []; + for (const val of def.values) { + if (val === undefined) { + if (this.unrepresentable === "throw") { + throw new Error("Literal `undefined` cannot be represented in JSON Schema"); + } + else { + // do not add to vals + } + } + else if (typeof val === "bigint") { + if (this.unrepresentable === "throw") { + throw new Error("BigInt literals cannot be represented in JSON Schema"); + } + else { + vals.push(Number(val)); + } + } + else { + vals.push(val); + } + } + if (vals.length === 0) { + // do nothing (an undefined literal was stripped) + } + else if (vals.length === 1) { + const val = vals[0]; + json.type = val === null ? "null" : typeof val; + json.const = val; + } + else { + if (vals.every((v) => typeof v === "number")) + json.type = "number"; + if (vals.every((v) => typeof v === "string")) + json.type = "string"; + if (vals.every((v) => typeof v === "boolean")) + json.type = "string"; + if (vals.every((v) => v === null)) + json.type = "null"; + json.enum = vals; + } + break; + } + case "file": { + const json = _json; + const file = { + type: "string", + format: "binary", + contentEncoding: "binary", + }; + const { minimum, maximum, mime } = schema._zod.bag; + if (minimum !== undefined) + file.minLength = minimum; + if (maximum !== undefined) + file.maxLength = maximum; + if (mime) { + if (mime.length === 1) { + file.contentMediaType = mime[0]; + Object.assign(json, file); + } + else { + json.anyOf = mime.map((m) => { + const mFile = { ...file, contentMediaType: m }; + return mFile; + }); + } + } + else { + Object.assign(json, file); + } + // if (this.unrepresentable === "throw") { + // throw new Error("File cannot be represented in JSON Schema"); + // } + break; + } + case "transform": { + if (this.unrepresentable === "throw") { + throw new Error("Transforms cannot be represented in JSON Schema"); + } + break; + } + case "nullable": { + const inner = this.process(def.innerType, params); + _json.anyOf = [inner, { type: "null" }]; + break; + } + case "nonoptional": { + this.process(def.innerType, params); + result.ref = def.innerType; + break; + } + case "success": { + const json = _json; + json.type = "boolean"; + break; + } + case "default": { + this.process(def.innerType, params); + result.ref = def.innerType; + _json.default = JSON.parse(JSON.stringify(def.defaultValue)); + break; + } + case "prefault": { + this.process(def.innerType, params); + result.ref = def.innerType; + if (this.io === "input") + _json._prefault = JSON.parse(JSON.stringify(def.defaultValue)); + break; + } + case "catch": { + // use conditionals + this.process(def.innerType, params); + result.ref = def.innerType; + let catchValue; + try { + catchValue = def.catchValue(undefined); + } + catch { + throw new Error("Dynamic catch values are not supported in JSON Schema"); + } + _json.default = catchValue; + break; + } + case "nan": { + if (this.unrepresentable === "throw") { + throw new Error("NaN cannot be represented in JSON Schema"); + } + break; + } + case "template_literal": { + const json = _json; + const pattern = schema._zod.pattern; + if (!pattern) + throw new Error("Pattern not found in template literal"); + json.type = "string"; + json.pattern = pattern.source; + break; + } + case "pipe": { + const innerType = this.io === "input" ? (def.in._zod.def.type === "transform" ? def.out : def.in) : def.out; + this.process(innerType, params); + result.ref = innerType; + break; + } + case "readonly": { + this.process(def.innerType, params); + result.ref = def.innerType; + _json.readOnly = true; + break; + } + // passthrough types + case "promise": { + this.process(def.innerType, params); + result.ref = def.innerType; + break; + } + case "optional": { + this.process(def.innerType, params); + result.ref = def.innerType; + break; + } + case "lazy": { + const innerType = schema._zod.innerType; + this.process(innerType, params); + result.ref = innerType; + break; + } + case "custom": { + if (this.unrepresentable === "throw") { + throw new Error("Custom types cannot be represented in JSON Schema"); + } + break; + } + default: { + def; + } + } + } + } + // metadata + const meta = this.metadataRegistry.get(schema); + if (meta) + Object.assign(result.schema, meta); + if (this.io === "input" && isTransforming(schema)) { + // examples/defaults only apply to output type of pipe + delete result.schema.examples; + delete result.schema.default; + } + // set prefault as default + if (this.io === "input" && result.schema._prefault) + (_a = result.schema).default ?? (_a.default = result.schema._prefault); + delete result.schema._prefault; + // pulling fresh from this.seen in case it was overwritten + const _result = this.seen.get(schema); + return _result.schema; + } + emit(schema, _params) { + const params = { + cycles: _params?.cycles ?? "ref", + reused: _params?.reused ?? "inline", + // unrepresentable: _params?.unrepresentable ?? "throw", + // uri: _params?.uri ?? ((id) => `${id}`), + external: _params?.external ?? undefined, + }; + // iterate over seen map; + const root = this.seen.get(schema); + if (!root) + throw new Error("Unprocessed schema. This is a bug in Zod."); + // initialize result with root schema fields + // Object.assign(result, seen.cached); + // returns a ref to the schema + // defId will be empty if the ref points to an external schema (or #) + const makeURI = (entry) => { + // comparing the seen objects because sometimes + // multiple schemas map to the same seen object. + // e.g. lazy + // external is configured + const defsSegment = this.target === "draft-2020-12" ? "$defs" : "definitions"; + if (params.external) { + const externalId = params.external.registry.get(entry[0])?.id; // ?? "__shared";// `__schema${this.counter++}`; + // check if schema is in the external registry + const uriGenerator = params.external.uri ?? ((id) => id); + if (externalId) { + return { ref: uriGenerator(externalId) }; + } + // otherwise, add to __shared + const id = entry[1].defId ?? entry[1].schema.id ?? `schema${this.counter++}`; + entry[1].defId = id; // set defId so it will be reused if needed + return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` }; + } + if (entry[1] === root) { + return { ref: "#" }; + } + // self-contained schema + const uriPrefix = `#`; + const defUriPrefix = `${uriPrefix}/${defsSegment}/`; + const defId = entry[1].schema.id ?? `__schema${this.counter++}`; + return { defId, ref: defUriPrefix + defId }; + }; + // stored cached version in `def` property + // remove all properties, set $ref + const extractToDef = (entry) => { + // if the schema is already a reference, do not extract it + if (entry[1].schema.$ref) { + return; + } + const seen = entry[1]; + const { ref, defId } = makeURI(entry); + seen.def = { ...seen.schema }; + // defId won't be set if the schema is a reference to an external schema + if (defId) + seen.defId = defId; + // wipe away all properties except $ref + const schema = seen.schema; + for (const key in schema) { + delete schema[key]; + } + schema.$ref = ref; + }; + // throw on cycles + // break cycles + if (params.cycles === "throw") { + for (const entry of this.seen.entries()) { + const seen = entry[1]; + if (seen.cycle) { + throw new Error("Cycle detected: " + + `#/${seen.cycle?.join("/")}/` + + '\n\nSet the `cycles` parameter to `"ref"` to resolve cyclical schemas with defs.'); + } + } + } + // extract schemas into $defs + for (const entry of this.seen.entries()) { + const seen = entry[1]; + // convert root schema to # $ref + if (schema === entry[0]) { + extractToDef(entry); // this has special handling for the root schema + continue; + } + // extract schemas that are in the external registry + if (params.external) { + const ext = params.external.registry.get(entry[0])?.id; + if (schema !== entry[0] && ext) { + extractToDef(entry); + continue; + } + } + // extract schemas with `id` meta + const id = this.metadataRegistry.get(entry[0])?.id; + if (id) { + extractToDef(entry); + continue; + } + // break cycles + if (seen.cycle) { + // any + extractToDef(entry); + continue; + } + // extract reused schemas + if (seen.count > 1) { + if (params.reused === "ref") { + extractToDef(entry); + // biome-ignore lint: + continue; + } + } + } + // flatten _refs + const flattenRef = (zodSchema, params) => { + const seen = this.seen.get(zodSchema); + const schema = seen.def ?? seen.schema; + const _cached = { ...schema }; + // already seen + if (seen.ref === null) { + return; + } + // flatten ref if defined + const ref = seen.ref; + seen.ref = null; // prevent recursion + if (ref) { + flattenRef(ref, params); + // merge referenced schema into current + const refSchema = this.seen.get(ref).schema; + if (refSchema.$ref && params.target === "draft-7") { + schema.allOf = schema.allOf ?? []; + schema.allOf.push(refSchema); + } + else { + Object.assign(schema, refSchema); + Object.assign(schema, _cached); // prevent overwriting any fields in the original schema + } + } + // execute overrides + if (!seen.isParent) + this.override({ + zodSchema: zodSchema, + jsonSchema: schema, + path: seen.path ?? [], + }); + }; + for (const entry of [...this.seen.entries()].reverse()) { + flattenRef(entry[0], { target: this.target }); + } + const result = {}; + if (this.target === "draft-2020-12") { + result.$schema = "https://json-schema.org/draft/2020-12/schema"; + } + else if (this.target === "draft-7") { + result.$schema = "http://json-schema.org/draft-07/schema#"; + } + else { + console.warn(`Invalid target: ${this.target}`); + } + if (params.external?.uri) { + const id = params.external.registry.get(schema)?.id; + if (!id) + throw new Error("Schema is missing an `id` property"); + result.$id = params.external.uri(id); + } + Object.assign(result, root.def); + // build defs object + const defs = params.external?.defs ?? {}; + for (const entry of this.seen.entries()) { + const seen = entry[1]; + if (seen.def && seen.defId) { + defs[seen.defId] = seen.def; + } + } + // set definitions in result + if (params.external) { + } + else { + if (Object.keys(defs).length > 0) { + if (this.target === "draft-2020-12") { + result.$defs = defs; + } + else { + result.definitions = defs; + } + } + } + try { + // this "finalizes" this schema and ensures all cycles are removed + // each call to .emit() is functionally independent + // though the seen map is shared + return JSON.parse(JSON.stringify(result)); + } + catch (_err) { + throw new Error("Error converting schema to JSON."); + } + } +} +function toJSONSchema(input, _params) { + if (input instanceof $ZodRegistry) { + const gen = new JSONSchemaGenerator(_params); + const defs = {}; + for (const entry of input._idmap.entries()) { + const [_, schema] = entry; + gen.process(schema); + } + const schemas = {}; + const external = { + registry: input, + uri: _params?.uri, + defs, + }; + for (const entry of input._idmap.entries()) { + const [key, schema] = entry; + schemas[key] = gen.emit(schema, { + ..._params, + external, + }); + } + if (Object.keys(defs).length > 0) { + const defsSegment = gen.target === "draft-2020-12" ? "$defs" : "definitions"; + schemas.__shared = { + [defsSegment]: defs, + }; + } + return { schemas }; + } + const gen = new JSONSchemaGenerator(_params); + gen.process(input); + return gen.emit(input, _params); +} +function isTransforming(_schema, _ctx) { + const ctx = _ctx ?? { seen: new Set() }; + if (ctx.seen.has(_schema)) + return false; + ctx.seen.add(_schema); + const schema = _schema; + const def = schema._zod.def; + switch (def.type) { + case "string": + case "number": + case "bigint": + case "boolean": + case "date": + case "symbol": + case "undefined": + case "null": + case "any": + case "unknown": + case "never": + case "void": + case "literal": + case "enum": + case "nan": + case "file": + case "template_literal": + return false; + case "array": { + return isTransforming(def.element, ctx); + } + case "object": { + for (const key in def.shape) { + if (isTransforming(def.shape[key], ctx)) + return true; + } + return false; + } + case "union": { + for (const option of def.options) { + if (isTransforming(option, ctx)) + return true; + } + return false; + } + case "intersection": { + return isTransforming(def.left, ctx) || isTransforming(def.right, ctx); + } + case "tuple": { + for (const item of def.items) { + if (isTransforming(item, ctx)) + return true; + } + if (def.rest && isTransforming(def.rest, ctx)) + return true; + return false; + } + case "record": { + return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + } + case "map": { + return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx); + } + case "set": { + return isTransforming(def.valueType, ctx); + } + // inner types + case "promise": + case "optional": + case "nonoptional": + case "nullable": + case "readonly": + return isTransforming(def.innerType, ctx); + case "lazy": + return isTransforming(def.getter(), ctx); + case "default": { + return isTransforming(def.innerType, ctx); + } + case "prefault": { + return isTransforming(def.innerType, ctx); + } + case "custom": { + return false; + } + case "transform": { + return true; + } + case "pipe": { + return isTransforming(def.in, ctx) || isTransforming(def.out, ctx); + } + case "success": { + return false; + } + case "catch": { + return false; + } + default: + def; + } + throw new Error(`Unknown schema type: ${def.type}`); +} + +;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/deep-compare-strict.js +function deepCompareStrict(a, b) { + const typeofa = typeof a; + if (typeofa !== typeof b) { + return false; + } + if (Array.isArray(a)) { + if (!Array.isArray(b)) { + return false; + } + const length = a.length; + if (length !== b.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (!deepCompareStrict(a[i], b[i])) { + return false; + } + } + return true; + } + if (typeofa === 'object') { + if (!a || !b) { + return a === b; + } + const aKeys = Object.keys(a); + const bKeys = Object.keys(b); + const length = aKeys.length; + if (length !== bKeys.length) { + return false; + } + for (const k of aKeys) { + if (!deepCompareStrict(a[k], b[k])) { + return false; + } + } + return true; + } + return a === b; +} -//# sourceMappingURL=vectorstores.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/js-sha256/hash.js +;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/pointer.js +function encodePointer(p) { + return encodeURI(escapePointer(p)); +} +function escapePointer(p) { + return p.replace(/~/g, '~0').replace(/\//g, '~1'); +} +;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/dereference.js -//#region src/utils/js-sha256/hash.ts -var HEX_CHARS = "0123456789abcdef".split(""); -var EXTRA = [ - -2147483648, - 8388608, - 32768, - 128 -]; -var SHIFT = [ - 24, - 16, - 8, - 0 -]; -var K = [ - 1116352408, - 1899447441, - 3049323471, - 3921009573, - 961987163, - 1508970993, - 2453635748, - 2870763221, - 3624381080, - 310598401, - 607225278, - 1426881987, - 1925078388, - 2162078206, - 2614888103, - 3248222580, - 3835390401, - 4022224774, - 264347078, - 604807628, - 770255983, - 1249150122, - 1555081692, - 1996064986, - 2554220882, - 2821834349, - 2952996808, - 3210313671, - 3336571891, - 3584528711, - 113926993, - 338241895, - 666307205, - 773529912, - 1294757372, - 1396182291, - 1695183700, - 1986661051, - 2177026350, - 2456956037, - 2730485921, - 2820302411, - 3259730800, - 3345764771, - 3516065817, - 3600352804, - 4094571909, - 275423344, - 430227734, - 506948616, - 659060556, - 883997877, - 958139571, - 1322822218, - 1537002063, - 1747873779, - 1955562222, - 2024104815, - 2227730452, - 2361852424, - 2428436474, - 2756734187, - 3204031479, - 3329325298 -]; -var blocks = []; -function Sha256(is224, sharedMemory) { - if (sharedMemory) { - blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; - this.blocks = blocks; - } else this.blocks = [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ]; - if (is224) { - this.h0 = 3238371032; - this.h1 = 914150663; - this.h2 = 812702999; - this.h3 = 4144912697; - this.h4 = 4290775857; - this.h5 = 1750603025; - this.h6 = 1694076839; - this.h7 = 3204075428; - } else { - this.h0 = 1779033703; - this.h1 = 3144134277; - this.h2 = 1013904242; - this.h3 = 2773480762; - this.h4 = 1359893119; - this.h5 = 2600822924; - this.h6 = 528734635; - this.h7 = 1541459225; - } - this.block = this.start = this.bytes = this.hBytes = 0; - this.finalized = this.hashed = false; - this.first = true; - this.is224 = is224; -} -Sha256.prototype.update = function(message) { - if (this.finalized) return; - var notString, type = typeof message; - if (type !== "string") { - if (type === "object") { - if (message === null) throw new Error(ERROR); - else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) message = new Uint8Array(message); - else if (!Array.isArray(message)) { - if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) throw new Error(ERROR); - } - } else throw new Error(ERROR); - notString = true; - } - var code, index = 0, i, length = message.length, blocks$1 = this.blocks; - while (index < length) { - if (this.hashed) { - this.hashed = false; - blocks$1[0] = this.block; - this.block = blocks$1[16] = blocks$1[1] = blocks$1[2] = blocks$1[3] = blocks$1[4] = blocks$1[5] = blocks$1[6] = blocks$1[7] = blocks$1[8] = blocks$1[9] = blocks$1[10] = blocks$1[11] = blocks$1[12] = blocks$1[13] = blocks$1[14] = blocks$1[15] = 0; - } - if (notString) for (i = this.start; index < length && i < 64; ++index) blocks$1[i >>> 2] |= message[index] << SHIFT[i++ & 3]; - else for (i = this.start; index < length && i < 64; ++index) { - code = message.charCodeAt(index); - if (code < 128) blocks$1[i >>> 2] |= code << SHIFT[i++ & 3]; - else if (code < 2048) { - blocks$1[i >>> 2] |= (192 | code >>> 6) << SHIFT[i++ & 3]; - blocks$1[i >>> 2] |= (128 | code & 63) << SHIFT[i++ & 3]; - } else if (code < 55296 || code >= 57344) { - blocks$1[i >>> 2] |= (224 | code >>> 12) << SHIFT[i++ & 3]; - blocks$1[i >>> 2] |= (128 | code >>> 6 & 63) << SHIFT[i++ & 3]; - blocks$1[i >>> 2] |= (128 | code & 63) << SHIFT[i++ & 3]; - } else { - code = 65536 + ((code & 1023) << 10 | message.charCodeAt(++index) & 1023); - blocks$1[i >>> 2] |= (240 | code >>> 18) << SHIFT[i++ & 3]; - blocks$1[i >>> 2] |= (128 | code >>> 12 & 63) << SHIFT[i++ & 3]; - blocks$1[i >>> 2] |= (128 | code >>> 6 & 63) << SHIFT[i++ & 3]; - blocks$1[i >>> 2] |= (128 | code & 63) << SHIFT[i++ & 3]; - } - } - this.lastByteIndex = i; - this.bytes += i - this.start; - if (i >= 64) { - this.block = blocks$1[16]; - this.start = i - 64; - this.hash(); - this.hashed = true; - } else this.start = i; - } - if (this.bytes > 4294967295) { - this.hBytes += this.bytes / 4294967296 << 0; - this.bytes = this.bytes % 4294967296; - } - return this; -}; -Sha256.prototype.finalize = function() { - if (this.finalized) return; - this.finalized = true; - var blocks$1 = this.blocks, i = this.lastByteIndex; - blocks$1[16] = this.block; - blocks$1[i >>> 2] |= EXTRA[i & 3]; - this.block = blocks$1[16]; - if (i >= 56) { - if (!this.hashed) this.hash(); - blocks$1[0] = this.block; - blocks$1[16] = blocks$1[1] = blocks$1[2] = blocks$1[3] = blocks$1[4] = blocks$1[5] = blocks$1[6] = blocks$1[7] = blocks$1[8] = blocks$1[9] = blocks$1[10] = blocks$1[11] = blocks$1[12] = blocks$1[13] = blocks$1[14] = blocks$1[15] = 0; - } - blocks$1[14] = this.hBytes << 3 | this.bytes >>> 29; - blocks$1[15] = this.bytes << 3; - this.hash(); -}; -Sha256.prototype.hash = function() { - var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4, f = this.h5, g = this.h6, h = this.h7, blocks$1 = this.blocks, j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc; - for (j = 16; j < 64; ++j) { - t1 = blocks$1[j - 15]; - s0 = (t1 >>> 7 | t1 << 25) ^ (t1 >>> 18 | t1 << 14) ^ t1 >>> 3; - t1 = blocks$1[j - 2]; - s1 = (t1 >>> 17 | t1 << 15) ^ (t1 >>> 19 | t1 << 13) ^ t1 >>> 10; - blocks$1[j] = blocks$1[j - 16] + s0 + blocks$1[j - 7] + s1 << 0; - } - bc = b & c; - for (j = 0; j < 64; j += 4) { - if (this.first) { - if (this.is224) { - ab = 300032; - t1 = blocks$1[0] - 1413257819; - h = t1 - 150054599 << 0; - d = t1 + 24177077 << 0; - } else { - ab = 704751109; - t1 = blocks$1[0] - 210244248; - h = t1 - 1521486534 << 0; - d = t1 + 143694565 << 0; - } - this.first = false; - } else { - s0 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10); - s1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7); - ab = a & b; - maj = ab ^ a & c ^ bc; - ch = e & f ^ ~e & g; - t1 = h + s1 + ch + K[j] + blocks$1[j]; - t2 = s0 + maj; - h = d + t1 << 0; - d = t1 + t2 << 0; - } - s0 = (d >>> 2 | d << 30) ^ (d >>> 13 | d << 19) ^ (d >>> 22 | d << 10); - s1 = (h >>> 6 | h << 26) ^ (h >>> 11 | h << 21) ^ (h >>> 25 | h << 7); - da = d & a; - maj = da ^ d & b ^ ab; - ch = g & h ^ ~g & e; - t1 = f + s1 + ch + K[j + 1] + blocks$1[j + 1]; - t2 = s0 + maj; - g = c + t1 << 0; - c = t1 + t2 << 0; - s0 = (c >>> 2 | c << 30) ^ (c >>> 13 | c << 19) ^ (c >>> 22 | c << 10); - s1 = (g >>> 6 | g << 26) ^ (g >>> 11 | g << 21) ^ (g >>> 25 | g << 7); - cd = c & d; - maj = cd ^ c & a ^ da; - ch = f & g ^ ~f & h; - t1 = e + s1 + ch + K[j + 2] + blocks$1[j + 2]; - t2 = s0 + maj; - f = b + t1 << 0; - b = t1 + t2 << 0; - s0 = (b >>> 2 | b << 30) ^ (b >>> 13 | b << 19) ^ (b >>> 22 | b << 10); - s1 = (f >>> 6 | f << 26) ^ (f >>> 11 | f << 21) ^ (f >>> 25 | f << 7); - bc = b & c; - maj = bc ^ b & d ^ cd; - ch = f & g ^ ~f & h; - t1 = e + s1 + ch + K[j + 3] + blocks$1[j + 3]; - t2 = s0 + maj; - e = a + t1 << 0; - a = t1 + t2 << 0; - this.chromeBugWorkAround = true; - } - this.h0 = this.h0 + a << 0; - this.h1 = this.h1 + b << 0; - this.h2 = this.h2 + c << 0; - this.h3 = this.h3 + d << 0; - this.h4 = this.h4 + e << 0; - this.h5 = this.h5 + f << 0; - this.h6 = this.h6 + g << 0; - this.h7 = this.h7 + h << 0; +const schemaKeyword = { + additionalItems: true, + unevaluatedItems: true, + items: true, + contains: true, + additionalProperties: true, + unevaluatedProperties: true, + propertyNames: true, + not: true, + if: true, + then: true, + else: true }; -Sha256.prototype.hex = function() { - this.finalize(); - var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, h6 = this.h6, h7 = this.h7; - var hex = HEX_CHARS[h0 >>> 28 & 15] + HEX_CHARS[h0 >>> 24 & 15] + HEX_CHARS[h0 >>> 20 & 15] + HEX_CHARS[h0 >>> 16 & 15] + HEX_CHARS[h0 >>> 12 & 15] + HEX_CHARS[h0 >>> 8 & 15] + HEX_CHARS[h0 >>> 4 & 15] + HEX_CHARS[h0 & 15] + HEX_CHARS[h1 >>> 28 & 15] + HEX_CHARS[h1 >>> 24 & 15] + HEX_CHARS[h1 >>> 20 & 15] + HEX_CHARS[h1 >>> 16 & 15] + HEX_CHARS[h1 >>> 12 & 15] + HEX_CHARS[h1 >>> 8 & 15] + HEX_CHARS[h1 >>> 4 & 15] + HEX_CHARS[h1 & 15] + HEX_CHARS[h2 >>> 28 & 15] + HEX_CHARS[h2 >>> 24 & 15] + HEX_CHARS[h2 >>> 20 & 15] + HEX_CHARS[h2 >>> 16 & 15] + HEX_CHARS[h2 >>> 12 & 15] + HEX_CHARS[h2 >>> 8 & 15] + HEX_CHARS[h2 >>> 4 & 15] + HEX_CHARS[h2 & 15] + HEX_CHARS[h3 >>> 28 & 15] + HEX_CHARS[h3 >>> 24 & 15] + HEX_CHARS[h3 >>> 20 & 15] + HEX_CHARS[h3 >>> 16 & 15] + HEX_CHARS[h3 >>> 12 & 15] + HEX_CHARS[h3 >>> 8 & 15] + HEX_CHARS[h3 >>> 4 & 15] + HEX_CHARS[h3 & 15] + HEX_CHARS[h4 >>> 28 & 15] + HEX_CHARS[h4 >>> 24 & 15] + HEX_CHARS[h4 >>> 20 & 15] + HEX_CHARS[h4 >>> 16 & 15] + HEX_CHARS[h4 >>> 12 & 15] + HEX_CHARS[h4 >>> 8 & 15] + HEX_CHARS[h4 >>> 4 & 15] + HEX_CHARS[h4 & 15] + HEX_CHARS[h5 >>> 28 & 15] + HEX_CHARS[h5 >>> 24 & 15] + HEX_CHARS[h5 >>> 20 & 15] + HEX_CHARS[h5 >>> 16 & 15] + HEX_CHARS[h5 >>> 12 & 15] + HEX_CHARS[h5 >>> 8 & 15] + HEX_CHARS[h5 >>> 4 & 15] + HEX_CHARS[h5 & 15] + HEX_CHARS[h6 >>> 28 & 15] + HEX_CHARS[h6 >>> 24 & 15] + HEX_CHARS[h6 >>> 20 & 15] + HEX_CHARS[h6 >>> 16 & 15] + HEX_CHARS[h6 >>> 12 & 15] + HEX_CHARS[h6 >>> 8 & 15] + HEX_CHARS[h6 >>> 4 & 15] + HEX_CHARS[h6 & 15]; - if (!this.is224) hex += HEX_CHARS[h7 >>> 28 & 15] + HEX_CHARS[h7 >>> 24 & 15] + HEX_CHARS[h7 >>> 20 & 15] + HEX_CHARS[h7 >>> 16 & 15] + HEX_CHARS[h7 >>> 12 & 15] + HEX_CHARS[h7 >>> 8 & 15] + HEX_CHARS[h7 >>> 4 & 15] + HEX_CHARS[h7 & 15]; - return hex; +const schemaArrayKeyword = { + prefixItems: true, + items: true, + allOf: true, + anyOf: true, + oneOf: true }; -Sha256.prototype.toString = Sha256.prototype.hex; -Sha256.prototype.digest = function() { - this.finalize(); - var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, h6 = this.h6, h7 = this.h7; - var arr = [ - h0 >>> 24 & 255, - h0 >>> 16 & 255, - h0 >>> 8 & 255, - h0 & 255, - h1 >>> 24 & 255, - h1 >>> 16 & 255, - h1 >>> 8 & 255, - h1 & 255, - h2 >>> 24 & 255, - h2 >>> 16 & 255, - h2 >>> 8 & 255, - h2 & 255, - h3 >>> 24 & 255, - h3 >>> 16 & 255, - h3 >>> 8 & 255, - h3 & 255, - h4 >>> 24 & 255, - h4 >>> 16 & 255, - h4 >>> 8 & 255, - h4 & 255, - h5 >>> 24 & 255, - h5 >>> 16 & 255, - h5 >>> 8 & 255, - h5 & 255, - h6 >>> 24 & 255, - h6 >>> 16 & 255, - h6 >>> 8 & 255, - h6 & 255 - ]; - if (!this.is224) arr.push(h7 >>> 24 & 255, h7 >>> 16 & 255, h7 >>> 8 & 255, h7 & 255); - return arr; +const schemaMapKeyword = { + $defs: true, + definitions: true, + properties: true, + patternProperties: true, + dependentSchemas: true }; -Sha256.prototype.array = Sha256.prototype.digest; -Sha256.prototype.arrayBuffer = function() { - this.finalize(); - var buffer = /* @__PURE__ */ new ArrayBuffer(this.is224 ? 28 : 32); - var dataView = new DataView(buffer); - dataView.setUint32(0, this.h0); - dataView.setUint32(4, this.h1); - dataView.setUint32(8, this.h2); - dataView.setUint32(12, this.h3); - dataView.setUint32(16, this.h4); - dataView.setUint32(20, this.h5); - dataView.setUint32(24, this.h6); - if (!this.is224) dataView.setUint32(28, this.h7); - return buffer; +const ignoredKeyword = { + id: true, + $id: true, + $ref: true, + $schema: true, + $anchor: true, + $vocabulary: true, + $comment: true, + default: true, + enum: true, + const: true, + required: true, + type: true, + maximum: true, + minimum: true, + exclusiveMaximum: true, + exclusiveMinimum: true, + multipleOf: true, + maxLength: true, + minLength: true, + pattern: true, + format: true, + maxItems: true, + minItems: true, + uniqueItems: true, + maxProperties: true, + minProperties: true }; -const sha256 = (...strings) => { - return new Sha256(false, true).update(strings.join("")).hex(); +let initialBaseURI = typeof self !== 'undefined' && + self.location && + self.location.origin !== 'null' + ? + new URL(self.location.origin + self.location.pathname + location.search) + : new URL('https://github.com/cfworker'); +function dereference(schema, lookup = Object.create(null), baseURI = initialBaseURI, basePointer = '') { + if (schema && typeof schema === 'object' && !Array.isArray(schema)) { + const id = schema.$id || schema.id; + if (id) { + const url = new URL(id, baseURI.href); + if (url.hash.length > 1) { + lookup[url.href] = schema; + } + else { + url.hash = ''; + if (basePointer === '') { + baseURI = url; + } + else { + dereference(schema, lookup, baseURI); + } + } + } + } + else if (schema !== true && schema !== false) { + return lookup; + } + const schemaURI = baseURI.href + (basePointer ? '#' + basePointer : ''); + if (lookup[schemaURI] !== undefined) { + throw new Error(`Duplicate schema URI "${schemaURI}".`); + } + lookup[schemaURI] = schema; + if (schema === true || schema === false) { + return lookup; + } + if (schema.__absolute_uri__ === undefined) { + Object.defineProperty(schema, '__absolute_uri__', { + enumerable: false, + value: schemaURI + }); + } + if (schema.$ref && schema.__absolute_ref__ === undefined) { + const url = new URL(schema.$ref, baseURI.href); + url.hash = url.hash; + Object.defineProperty(schema, '__absolute_ref__', { + enumerable: false, + value: url.href + }); + } + if (schema.$recursiveRef && schema.__absolute_recursive_ref__ === undefined) { + const url = new URL(schema.$recursiveRef, baseURI.href); + url.hash = url.hash; + Object.defineProperty(schema, '__absolute_recursive_ref__', { + enumerable: false, + value: url.href + }); + } + if (schema.$anchor) { + const url = new URL('#' + schema.$anchor, baseURI.href); + lookup[url.href] = schema; + } + for (let key in schema) { + if (ignoredKeyword[key]) { + continue; + } + const keyBase = `${basePointer}/${encodePointer(key)}`; + const subSchema = schema[key]; + if (Array.isArray(subSchema)) { + if (schemaArrayKeyword[key]) { + const length = subSchema.length; + for (let i = 0; i < length; i++) { + dereference(subSchema[i], lookup, baseURI, `${keyBase}/${i}`); + } + } + } + else if (schemaMapKeyword[key]) { + for (let subKey in subSchema) { + dereference(subSchema[subKey], lookup, baseURI, `${keyBase}/${encodePointer(subKey)}`); + } + } + else { + dereference(subSchema, lookup, baseURI, keyBase); + } + } + return lookup; +} + +;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/format.js +const DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/; +const DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; +const TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i; +const HOSTNAME = /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i; +const URIREF = /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; +const URITEMPLATE = /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i; +const URL_ = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)(?:\.(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu; +const UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i; +const JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$/; +const JSON_POINTER_URI_FRAGMENT = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i; +const RELATIVE_JSON_POINTER = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/; +const EMAIL = (input) => { + if (input[0] === '"') + return false; + const [name, host, ...rest] = input.split('@'); + if (!name || + !host || + rest.length !== 0 || + name.length > 64 || + host.length > 253) + return false; + if (name[0] === '.' || name.endsWith('.') || name.includes('..')) + return false; + if (!/^[a-z0-9.-]+$/i.test(host) || + !/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+$/i.test(name)) + return false; + return host + .split('.') + .every(part => /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(part)); +}; +const IPV4 = /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/; +const IPV6 = /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i; +const DURATION = (input) => input.length > 1 && + input.length < 80 && + (/^P\d+([.,]\d+)?W$/.test(input) || + (/^P[\dYMDTHS]*(\d[.,]\d+)?[YMDHS]$/.test(input) && + /^P([.,\d]+Y)?([.,\d]+M)?([.,\d]+D)?(T([.,\d]+H)?([.,\d]+M)?([.,\d]+S)?)?$/.test(input))); +function bind(r) { + return r.test.bind(r); +} +const format = { + date: format_date, + time: format_time.bind(undefined, false), + 'date-time': date_time, + duration: DURATION, + uri, + 'uri-reference': bind(URIREF), + 'uri-template': bind(URITEMPLATE), + url: bind(URL_), + email: EMAIL, + hostname: bind(HOSTNAME), + ipv4: bind(IPV4), + ipv6: bind(IPV6), + regex: regex, + uuid: bind(UUID), + 'json-pointer': bind(JSON_POINTER), + 'json-pointer-uri-fragment': bind(JSON_POINTER_URI_FRAGMENT), + 'relative-json-pointer': bind(RELATIVE_JSON_POINTER) }; +function isLeapYear(year) { + return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); +} +function format_date(str) { + const matches = str.match(DATE); + if (!matches) + return false; + const year = +matches[1]; + const month = +matches[2]; + const day = +matches[3]; + return (month >= 1 && + month <= 12 && + day >= 1 && + day <= (month == 2 && isLeapYear(year) ? 29 : DAYS[month])); +} +function format_time(full, str) { + const matches = str.match(TIME); + if (!matches) + return false; + const hour = +matches[1]; + const minute = +matches[2]; + const second = +matches[3]; + const timeZone = !!matches[5]; + return (((hour <= 23 && minute <= 59 && second <= 59) || + (hour == 23 && minute == 59 && second == 60)) && + (!full || timeZone)); +} +const DATE_TIME_SEPARATOR = /t|\s/i; +function date_time(str) { + const dateTime = str.split(DATE_TIME_SEPARATOR); + return dateTime.length == 2 && format_date(dateTime[0]) && format_time(true, dateTime[1]); +} +const NOT_URI_FRAGMENT = /\/|:/; +const URI_PATTERN = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; +function uri(str) { + return NOT_URI_FRAGMENT.test(str) && URI_PATTERN.test(str); +} +const Z_ANCHOR = /[^\\]\\Z/; +function regex(str) { + if (Z_ANCHOR.test(str)) + return false; + try { + new RegExp(str, 'u'); + return true; + } + catch (e) { + return false; + } +} + +;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/types.js +var OutputFormat; +(function (OutputFormat) { + OutputFormat[OutputFormat["Flag"] = 1] = "Flag"; + OutputFormat[OutputFormat["Basic"] = 2] = "Basic"; + OutputFormat[OutputFormat["Detailed"] = 4] = "Detailed"; +})(OutputFormat || (OutputFormat = {})); + +;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/ucs2-length.js +function ucs2length(s) { + let result = 0; + let length = s.length; + let index = 0; + let charCode; + while (index < length) { + result++; + charCode = s.charCodeAt(index++); + if (charCode >= 0xd800 && charCode <= 0xdbff && index < length) { + charCode = s.charCodeAt(index); + if ((charCode & 0xfc00) == 0xdc00) { + index++; + } + } + } + return result; +} + +;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/validate.js + + + + + +function validate_validate(instance, schema, draft = '2019-09', lookup = dereference(schema), shortCircuit = true, recursiveAnchor = null, instanceLocation = '#', schemaLocation = '#', evaluated = Object.create(null)) { + if (schema === true) { + return { valid: true, errors: [] }; + } + if (schema === false) { + return { + valid: false, + errors: [ + { + instanceLocation, + keyword: 'false', + keywordLocation: instanceLocation, + error: 'False boolean schema.' + } + ] + }; + } + const rawInstanceType = typeof instance; + let instanceType; + switch (rawInstanceType) { + case 'boolean': + case 'number': + case 'string': + instanceType = rawInstanceType; + break; + case 'object': + if (instance === null) { + instanceType = 'null'; + } + else if (Array.isArray(instance)) { + instanceType = 'array'; + } + else { + instanceType = 'object'; + } + break; + default: + throw new Error(`Instances of "${rawInstanceType}" type are not supported.`); + } + const { $ref, $recursiveRef, $recursiveAnchor, type: $type, const: $const, enum: $enum, required: $required, not: $not, anyOf: $anyOf, allOf: $allOf, oneOf: $oneOf, if: $if, then: $then, else: $else, format: $format, properties: $properties, patternProperties: $patternProperties, additionalProperties: $additionalProperties, unevaluatedProperties: $unevaluatedProperties, minProperties: $minProperties, maxProperties: $maxProperties, propertyNames: $propertyNames, dependentRequired: $dependentRequired, dependentSchemas: $dependentSchemas, dependencies: $dependencies, prefixItems: $prefixItems, items: $items, additionalItems: $additionalItems, unevaluatedItems: $unevaluatedItems, contains: $contains, minContains: $minContains, maxContains: $maxContains, minItems: $minItems, maxItems: $maxItems, uniqueItems: $uniqueItems, minimum: $minimum, maximum: $maximum, exclusiveMinimum: $exclusiveMinimum, exclusiveMaximum: $exclusiveMaximum, multipleOf: $multipleOf, minLength: $minLength, maxLength: $maxLength, pattern: $pattern, __absolute_ref__, __absolute_recursive_ref__ } = schema; + const errors = []; + if ($recursiveAnchor === true && recursiveAnchor === null) { + recursiveAnchor = schema; + } + if ($recursiveRef === '#') { + const refSchema = recursiveAnchor === null + ? lookup[__absolute_recursive_ref__] + : recursiveAnchor; + const keywordLocation = `${schemaLocation}/$recursiveRef`; + const result = validate_validate(instance, recursiveAnchor === null ? schema : recursiveAnchor, draft, lookup, shortCircuit, refSchema, instanceLocation, keywordLocation, evaluated); + if (!result.valid) { + errors.push({ + instanceLocation, + keyword: '$recursiveRef', + keywordLocation, + error: 'A subschema had errors.' + }, ...result.errors); + } + } + if ($ref !== undefined) { + const uri = __absolute_ref__ || $ref; + const refSchema = lookup[uri]; + if (refSchema === undefined) { + let message = `Unresolved $ref "${$ref}".`; + if (__absolute_ref__ && __absolute_ref__ !== $ref) { + message += ` Absolute URI "${__absolute_ref__}".`; + } + message += `\nKnown schemas:\n- ${Object.keys(lookup).join('\n- ')}`; + throw new Error(message); + } + const keywordLocation = `${schemaLocation}/$ref`; + const result = validate_validate(instance, refSchema, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, keywordLocation, evaluated); + if (!result.valid) { + errors.push({ + instanceLocation, + keyword: '$ref', + keywordLocation, + error: 'A subschema had errors.' + }, ...result.errors); + } + if (draft === '4' || draft === '7') { + return { valid: errors.length === 0, errors }; + } + } + if (Array.isArray($type)) { + let length = $type.length; + let valid = false; + for (let i = 0; i < length; i++) { + if (instanceType === $type[i] || + ($type[i] === 'integer' && + instanceType === 'number' && + instance % 1 === 0 && + instance === instance)) { + valid = true; + break; + } + } + if (!valid) { + errors.push({ + instanceLocation, + keyword: 'type', + keywordLocation: `${schemaLocation}/type`, + error: `Instance type "${instanceType}" is invalid. Expected "${$type.join('", "')}".` + }); + } + } + else if ($type === 'integer') { + if (instanceType !== 'number' || instance % 1 || instance !== instance) { + errors.push({ + instanceLocation, + keyword: 'type', + keywordLocation: `${schemaLocation}/type`, + error: `Instance type "${instanceType}" is invalid. Expected "${$type}".` + }); + } + } + else if ($type !== undefined && instanceType !== $type) { + errors.push({ + instanceLocation, + keyword: 'type', + keywordLocation: `${schemaLocation}/type`, + error: `Instance type "${instanceType}" is invalid. Expected "${$type}".` + }); + } + if ($const !== undefined) { + if (instanceType === 'object' || instanceType === 'array') { + if (!deepCompareStrict(instance, $const)) { + errors.push({ + instanceLocation, + keyword: 'const', + keywordLocation: `${schemaLocation}/const`, + error: `Instance does not match ${JSON.stringify($const)}.` + }); + } + } + else if (instance !== $const) { + errors.push({ + instanceLocation, + keyword: 'const', + keywordLocation: `${schemaLocation}/const`, + error: `Instance does not match ${JSON.stringify($const)}.` + }); + } + } + if ($enum !== undefined) { + if (instanceType === 'object' || instanceType === 'array') { + if (!$enum.some(value => deepCompareStrict(instance, value))) { + errors.push({ + instanceLocation, + keyword: 'enum', + keywordLocation: `${schemaLocation}/enum`, + error: `Instance does not match any of ${JSON.stringify($enum)}.` + }); + } + } + else if (!$enum.some(value => instance === value)) { + errors.push({ + instanceLocation, + keyword: 'enum', + keywordLocation: `${schemaLocation}/enum`, + error: `Instance does not match any of ${JSON.stringify($enum)}.` + }); + } + } + if ($not !== undefined) { + const keywordLocation = `${schemaLocation}/not`; + const result = validate_validate(instance, $not, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, keywordLocation); + if (result.valid) { + errors.push({ + instanceLocation, + keyword: 'not', + keywordLocation, + error: 'Instance matched "not" schema.' + }); + } + } + let subEvaluateds = []; + if ($anyOf !== undefined) { + const keywordLocation = `${schemaLocation}/anyOf`; + const errorsLength = errors.length; + let anyValid = false; + for (let i = 0; i < $anyOf.length; i++) { + const subSchema = $anyOf[i]; + const subEvaluated = Object.create(evaluated); + const result = validate_validate(instance, subSchema, draft, lookup, shortCircuit, $recursiveAnchor === true ? recursiveAnchor : null, instanceLocation, `${keywordLocation}/${i}`, subEvaluated); + errors.push(...result.errors); + anyValid = anyValid || result.valid; + if (result.valid) { + subEvaluateds.push(subEvaluated); + } + } + if (anyValid) { + errors.length = errorsLength; + } + else { + errors.splice(errorsLength, 0, { + instanceLocation, + keyword: 'anyOf', + keywordLocation, + error: 'Instance does not match any subschemas.' + }); + } + } + if ($allOf !== undefined) { + const keywordLocation = `${schemaLocation}/allOf`; + const errorsLength = errors.length; + let allValid = true; + for (let i = 0; i < $allOf.length; i++) { + const subSchema = $allOf[i]; + const subEvaluated = Object.create(evaluated); + const result = validate_validate(instance, subSchema, draft, lookup, shortCircuit, $recursiveAnchor === true ? recursiveAnchor : null, instanceLocation, `${keywordLocation}/${i}`, subEvaluated); + errors.push(...result.errors); + allValid = allValid && result.valid; + if (result.valid) { + subEvaluateds.push(subEvaluated); + } + } + if (allValid) { + errors.length = errorsLength; + } + else { + errors.splice(errorsLength, 0, { + instanceLocation, + keyword: 'allOf', + keywordLocation, + error: `Instance does not match every subschema.` + }); + } + } + if ($oneOf !== undefined) { + const keywordLocation = `${schemaLocation}/oneOf`; + const errorsLength = errors.length; + const matches = $oneOf.filter((subSchema, i) => { + const subEvaluated = Object.create(evaluated); + const result = validate_validate(instance, subSchema, draft, lookup, shortCircuit, $recursiveAnchor === true ? recursiveAnchor : null, instanceLocation, `${keywordLocation}/${i}`, subEvaluated); + errors.push(...result.errors); + if (result.valid) { + subEvaluateds.push(subEvaluated); + } + return result.valid; + }).length; + if (matches === 1) { + errors.length = errorsLength; + } + else { + errors.splice(errorsLength, 0, { + instanceLocation, + keyword: 'oneOf', + keywordLocation, + error: `Instance does not match exactly one subschema (${matches} matches).` + }); + } + } + if (instanceType === 'object' || instanceType === 'array') { + Object.assign(evaluated, ...subEvaluateds); + } + if ($if !== undefined) { + const keywordLocation = `${schemaLocation}/if`; + const conditionResult = validate_validate(instance, $if, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, keywordLocation, evaluated).valid; + if (conditionResult) { + if ($then !== undefined) { + const thenResult = validate_validate(instance, $then, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, `${schemaLocation}/then`, evaluated); + if (!thenResult.valid) { + errors.push({ + instanceLocation, + keyword: 'if', + keywordLocation, + error: `Instance does not match "then" schema.` + }, ...thenResult.errors); + } + } + } + else if ($else !== undefined) { + const elseResult = validate_validate(instance, $else, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, `${schemaLocation}/else`, evaluated); + if (!elseResult.valid) { + errors.push({ + instanceLocation, + keyword: 'if', + keywordLocation, + error: `Instance does not match "else" schema.` + }, ...elseResult.errors); + } + } + } + if (instanceType === 'object') { + if ($required !== undefined) { + for (const key of $required) { + if (!(key in instance)) { + errors.push({ + instanceLocation, + keyword: 'required', + keywordLocation: `${schemaLocation}/required`, + error: `Instance does not have required property "${key}".` + }); + } + } + } + const keys = Object.keys(instance); + if ($minProperties !== undefined && keys.length < $minProperties) { + errors.push({ + instanceLocation, + keyword: 'minProperties', + keywordLocation: `${schemaLocation}/minProperties`, + error: `Instance does not have at least ${$minProperties} properties.` + }); + } + if ($maxProperties !== undefined && keys.length > $maxProperties) { + errors.push({ + instanceLocation, + keyword: 'maxProperties', + keywordLocation: `${schemaLocation}/maxProperties`, + error: `Instance does not have at least ${$maxProperties} properties.` + }); + } + if ($propertyNames !== undefined) { + const keywordLocation = `${schemaLocation}/propertyNames`; + for (const key in instance) { + const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; + const result = validate_validate(key, $propertyNames, draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, keywordLocation); + if (!result.valid) { + errors.push({ + instanceLocation, + keyword: 'propertyNames', + keywordLocation, + error: `Property name "${key}" does not match schema.` + }, ...result.errors); + } + } + } + if ($dependentRequired !== undefined) { + const keywordLocation = `${schemaLocation}/dependantRequired`; + for (const key in $dependentRequired) { + if (key in instance) { + const required = $dependentRequired[key]; + for (const dependantKey of required) { + if (!(dependantKey in instance)) { + errors.push({ + instanceLocation, + keyword: 'dependentRequired', + keywordLocation, + error: `Instance has "${key}" but does not have "${dependantKey}".` + }); + } + } + } + } + } + if ($dependentSchemas !== undefined) { + for (const key in $dependentSchemas) { + const keywordLocation = `${schemaLocation}/dependentSchemas`; + if (key in instance) { + const result = validate_validate(instance, $dependentSchemas[key], draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, `${keywordLocation}/${encodePointer(key)}`, evaluated); + if (!result.valid) { + errors.push({ + instanceLocation, + keyword: 'dependentSchemas', + keywordLocation, + error: `Instance has "${key}" but does not match dependant schema.` + }, ...result.errors); + } + } + } + } + if ($dependencies !== undefined) { + const keywordLocation = `${schemaLocation}/dependencies`; + for (const key in $dependencies) { + if (key in instance) { + const propsOrSchema = $dependencies[key]; + if (Array.isArray(propsOrSchema)) { + for (const dependantKey of propsOrSchema) { + if (!(dependantKey in instance)) { + errors.push({ + instanceLocation, + keyword: 'dependencies', + keywordLocation, + error: `Instance has "${key}" but does not have "${dependantKey}".` + }); + } + } + } + else { + const result = validate_validate(instance, propsOrSchema, draft, lookup, shortCircuit, recursiveAnchor, instanceLocation, `${keywordLocation}/${encodePointer(key)}`); + if (!result.valid) { + errors.push({ + instanceLocation, + keyword: 'dependencies', + keywordLocation, + error: `Instance has "${key}" but does not match dependant schema.` + }, ...result.errors); + } + } + } + } + } + const thisEvaluated = Object.create(null); + let stop = false; + if ($properties !== undefined) { + const keywordLocation = `${schemaLocation}/properties`; + for (const key in $properties) { + if (!(key in instance)) { + continue; + } + const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; + const result = validate_validate(instance[key], $properties[key], draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, `${keywordLocation}/${encodePointer(key)}`); + if (result.valid) { + evaluated[key] = thisEvaluated[key] = true; + } + else { + stop = shortCircuit; + errors.push({ + instanceLocation, + keyword: 'properties', + keywordLocation, + error: `Property "${key}" does not match schema.` + }, ...result.errors); + if (stop) + break; + } + } + } + if (!stop && $patternProperties !== undefined) { + const keywordLocation = `${schemaLocation}/patternProperties`; + for (const pattern in $patternProperties) { + const regex = new RegExp(pattern, 'u'); + const subSchema = $patternProperties[pattern]; + for (const key in instance) { + if (!regex.test(key)) { + continue; + } + const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; + const result = validate_validate(instance[key], subSchema, draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, `${keywordLocation}/${encodePointer(pattern)}`); + if (result.valid) { + evaluated[key] = thisEvaluated[key] = true; + } + else { + stop = shortCircuit; + errors.push({ + instanceLocation, + keyword: 'patternProperties', + keywordLocation, + error: `Property "${key}" matches pattern "${pattern}" but does not match associated schema.` + }, ...result.errors); + } + } + } + } + if (!stop && $additionalProperties !== undefined) { + const keywordLocation = `${schemaLocation}/additionalProperties`; + for (const key in instance) { + if (thisEvaluated[key]) { + continue; + } + const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; + const result = validate_validate(instance[key], $additionalProperties, draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, keywordLocation); + if (result.valid) { + evaluated[key] = true; + } + else { + stop = shortCircuit; + errors.push({ + instanceLocation, + keyword: 'additionalProperties', + keywordLocation, + error: `Property "${key}" does not match additional properties schema.` + }, ...result.errors); + } + } + } + else if (!stop && $unevaluatedProperties !== undefined) { + const keywordLocation = `${schemaLocation}/unevaluatedProperties`; + for (const key in instance) { + if (!evaluated[key]) { + const subInstancePointer = `${instanceLocation}/${encodePointer(key)}`; + const result = validate_validate(instance[key], $unevaluatedProperties, draft, lookup, shortCircuit, recursiveAnchor, subInstancePointer, keywordLocation); + if (result.valid) { + evaluated[key] = true; + } + else { + errors.push({ + instanceLocation, + keyword: 'unevaluatedProperties', + keywordLocation, + error: `Property "${key}" does not match unevaluated properties schema.` + }, ...result.errors); + } + } + } + } + } + else if (instanceType === 'array') { + if ($maxItems !== undefined && instance.length > $maxItems) { + errors.push({ + instanceLocation, + keyword: 'maxItems', + keywordLocation: `${schemaLocation}/maxItems`, + error: `Array has too many items (${instance.length} > ${$maxItems}).` + }); + } + if ($minItems !== undefined && instance.length < $minItems) { + errors.push({ + instanceLocation, + keyword: 'minItems', + keywordLocation: `${schemaLocation}/minItems`, + error: `Array has too few items (${instance.length} < ${$minItems}).` + }); + } + const length = instance.length; + let i = 0; + let stop = false; + if ($prefixItems !== undefined) { + const keywordLocation = `${schemaLocation}/prefixItems`; + const length2 = Math.min($prefixItems.length, length); + for (; i < length2; i++) { + const result = validate_validate(instance[i], $prefixItems[i], draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, `${keywordLocation}/${i}`); + evaluated[i] = true; + if (!result.valid) { + stop = shortCircuit; + errors.push({ + instanceLocation, + keyword: 'prefixItems', + keywordLocation, + error: `Items did not match schema.` + }, ...result.errors); + if (stop) + break; + } + } + } + if ($items !== undefined) { + const keywordLocation = `${schemaLocation}/items`; + if (Array.isArray($items)) { + const length2 = Math.min($items.length, length); + for (; i < length2; i++) { + const result = validate_validate(instance[i], $items[i], draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, `${keywordLocation}/${i}`); + evaluated[i] = true; + if (!result.valid) { + stop = shortCircuit; + errors.push({ + instanceLocation, + keyword: 'items', + keywordLocation, + error: `Items did not match schema.` + }, ...result.errors); + if (stop) + break; + } + } + } + else { + for (; i < length; i++) { + const result = validate_validate(instance[i], $items, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, keywordLocation); + evaluated[i] = true; + if (!result.valid) { + stop = shortCircuit; + errors.push({ + instanceLocation, + keyword: 'items', + keywordLocation, + error: `Items did not match schema.` + }, ...result.errors); + if (stop) + break; + } + } + } + if (!stop && $additionalItems !== undefined) { + const keywordLocation = `${schemaLocation}/additionalItems`; + for (; i < length; i++) { + const result = validate_validate(instance[i], $additionalItems, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, keywordLocation); + evaluated[i] = true; + if (!result.valid) { + stop = shortCircuit; + errors.push({ + instanceLocation, + keyword: 'additionalItems', + keywordLocation, + error: `Items did not match additional items schema.` + }, ...result.errors); + } + } + } + } + if ($contains !== undefined) { + if (length === 0 && $minContains === undefined) { + errors.push({ + instanceLocation, + keyword: 'contains', + keywordLocation: `${schemaLocation}/contains`, + error: `Array is empty. It must contain at least one item matching the schema.` + }); + } + else if ($minContains !== undefined && length < $minContains) { + errors.push({ + instanceLocation, + keyword: 'minContains', + keywordLocation: `${schemaLocation}/minContains`, + error: `Array has less items (${length}) than minContains (${$minContains}).` + }); + } + else { + const keywordLocation = `${schemaLocation}/contains`; + const errorsLength = errors.length; + let contained = 0; + for (let j = 0; j < length; j++) { + const result = validate_validate(instance[j], $contains, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${j}`, keywordLocation); + if (result.valid) { + evaluated[j] = true; + contained++; + } + else { + errors.push(...result.errors); + } + } + if (contained >= ($minContains || 0)) { + errors.length = errorsLength; + } + if ($minContains === undefined && + $maxContains === undefined && + contained === 0) { + errors.splice(errorsLength, 0, { + instanceLocation, + keyword: 'contains', + keywordLocation, + error: `Array does not contain item matching schema.` + }); + } + else if ($minContains !== undefined && contained < $minContains) { + errors.push({ + instanceLocation, + keyword: 'minContains', + keywordLocation: `${schemaLocation}/minContains`, + error: `Array must contain at least ${$minContains} items matching schema. Only ${contained} items were found.` + }); + } + else if ($maxContains !== undefined && contained > $maxContains) { + errors.push({ + instanceLocation, + keyword: 'maxContains', + keywordLocation: `${schemaLocation}/maxContains`, + error: `Array may contain at most ${$maxContains} items matching schema. ${contained} items were found.` + }); + } + } + } + if (!stop && $unevaluatedItems !== undefined) { + const keywordLocation = `${schemaLocation}/unevaluatedItems`; + for (i; i < length; i++) { + if (evaluated[i]) { + continue; + } + const result = validate_validate(instance[i], $unevaluatedItems, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${i}`, keywordLocation); + evaluated[i] = true; + if (!result.valid) { + errors.push({ + instanceLocation, + keyword: 'unevaluatedItems', + keywordLocation, + error: `Items did not match unevaluated items schema.` + }, ...result.errors); + } + } + } + if ($uniqueItems) { + for (let j = 0; j < length; j++) { + const a = instance[j]; + const ao = typeof a === 'object' && a !== null; + for (let k = 0; k < length; k++) { + if (j === k) { + continue; + } + const b = instance[k]; + const bo = typeof b === 'object' && b !== null; + if (a === b || (ao && bo && deepCompareStrict(a, b))) { + errors.push({ + instanceLocation, + keyword: 'uniqueItems', + keywordLocation: `${schemaLocation}/uniqueItems`, + error: `Duplicate items at indexes ${j} and ${k}.` + }); + j = Number.MAX_SAFE_INTEGER; + k = Number.MAX_SAFE_INTEGER; + } + } + } + } + } + else if (instanceType === 'number') { + if (draft === '4') { + if ($minimum !== undefined && + (($exclusiveMinimum === true && instance <= $minimum) || + instance < $minimum)) { + errors.push({ + instanceLocation, + keyword: 'minimum', + keywordLocation: `${schemaLocation}/minimum`, + error: `${instance} is less than ${$exclusiveMinimum ? 'or equal to ' : ''} ${$minimum}.` + }); + } + if ($maximum !== undefined && + (($exclusiveMaximum === true && instance >= $maximum) || + instance > $maximum)) { + errors.push({ + instanceLocation, + keyword: 'maximum', + keywordLocation: `${schemaLocation}/maximum`, + error: `${instance} is greater than ${$exclusiveMaximum ? 'or equal to ' : ''} ${$maximum}.` + }); + } + } + else { + if ($minimum !== undefined && instance < $minimum) { + errors.push({ + instanceLocation, + keyword: 'minimum', + keywordLocation: `${schemaLocation}/minimum`, + error: `${instance} is less than ${$minimum}.` + }); + } + if ($maximum !== undefined && instance > $maximum) { + errors.push({ + instanceLocation, + keyword: 'maximum', + keywordLocation: `${schemaLocation}/maximum`, + error: `${instance} is greater than ${$maximum}.` + }); + } + if ($exclusiveMinimum !== undefined && instance <= $exclusiveMinimum) { + errors.push({ + instanceLocation, + keyword: 'exclusiveMinimum', + keywordLocation: `${schemaLocation}/exclusiveMinimum`, + error: `${instance} is less than ${$exclusiveMinimum}.` + }); + } + if ($exclusiveMaximum !== undefined && instance >= $exclusiveMaximum) { + errors.push({ + instanceLocation, + keyword: 'exclusiveMaximum', + keywordLocation: `${schemaLocation}/exclusiveMaximum`, + error: `${instance} is greater than or equal to ${$exclusiveMaximum}.` + }); + } + } + if ($multipleOf !== undefined) { + const remainder = instance % $multipleOf; + if (Math.abs(0 - remainder) >= 1.1920929e-7 && + Math.abs($multipleOf - remainder) >= 1.1920929e-7) { + errors.push({ + instanceLocation, + keyword: 'multipleOf', + keywordLocation: `${schemaLocation}/multipleOf`, + error: `${instance} is not a multiple of ${$multipleOf}.` + }); + } + } + } + else if (instanceType === 'string') { + const length = $minLength === undefined && $maxLength === undefined + ? 0 + : ucs2length(instance); + if ($minLength !== undefined && length < $minLength) { + errors.push({ + instanceLocation, + keyword: 'minLength', + keywordLocation: `${schemaLocation}/minLength`, + error: `String is too short (${length} < ${$minLength}).` + }); + } + if ($maxLength !== undefined && length > $maxLength) { + errors.push({ + instanceLocation, + keyword: 'maxLength', + keywordLocation: `${schemaLocation}/maxLength`, + error: `String is too long (${length} > ${$maxLength}).` + }); + } + if ($pattern !== undefined && !new RegExp($pattern, 'u').test(instance)) { + errors.push({ + instanceLocation, + keyword: 'pattern', + keywordLocation: `${schemaLocation}/pattern`, + error: `String does not match pattern.` + }); + } + if ($format !== undefined && + format[$format] && + !format[$format](instance)) { + errors.push({ + instanceLocation, + keyword: 'format', + keywordLocation: `${schemaLocation}/format`, + error: `String does not match format "${$format}".` + }); + } + } + return { valid: errors.length === 0, errors }; +} -//#endregion +;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/validator.js -//# sourceMappingURL=hash.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/hash.js +class Validator { + schema; + draft; + shortCircuit; + lookup; + constructor(schema, draft = '2019-09', shortCircuit = true) { + this.schema = schema; + this.draft = draft; + this.shortCircuit = shortCircuit; + this.lookup = dereference(schema); + } + validate(instance) { + return validate_validate(instance, this.schema, this.draft, this.lookup, this.shortCircuit); + } + addSchema(schema, id) { + if (id) { + schema = { ...schema, $id: id }; + } + dereference(schema, this.lookup); + } +} + +;// CONCATENATED MODULE: ./node_modules/@cfworker/json-schema/dist/esm/index.js -//#region src/utils/hash.ts -var hash_exports = {}; -__export(hash_exports, { sha256: () => sha256 }); -//#endregion -//# sourceMappingURL=hash.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/caches/index.js -//#region src/caches/index.ts -var caches_exports = {}; -__export(caches_exports, { - BaseCache: () => caches_BaseCache, - InMemoryCache: () => InMemoryCache, - defaultHashKeyEncoder: () => defaultHashKeyEncoder, - deserializeStoredGeneration: () => deserializeStoredGeneration, - serializeGeneration: () => serializeGeneration +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/json_schema.js + + + + + + + +//#region src/utils/json_schema.ts +var json_schema_exports = {}; +__export(json_schema_exports, { + Validator: () => Validator, + deepCompareStrict: () => deepCompareStrict, + toJsonSchema: () => toJsonSchema, + validatesOnlyStrings: () => validatesOnlyStrings }); -const defaultHashKeyEncoder = (...strings) => sha256(strings.join("_")); -function deserializeStoredGeneration(storedGeneration) { - if (storedGeneration.message !== void 0) return { - text: storedGeneration.text, - message: mapStoredMessageToChatMessage(storedGeneration.message) - }; - else return { text: storedGeneration.text }; +/** +* Converts a Zod schema or JSON schema to a JSON schema. +* @param schema - The schema to convert. +* @param params - The parameters to pass to the toJSONSchema function. +* @returns The converted schema. +*/ +function toJsonSchema(schema, params) { + if (isZodSchemaV4(schema)) { + const inputSchema = interopZodTransformInputSchema(schema, true); + if (isZodObjectV4(inputSchema)) { + const strictSchema = interopZodObjectStrict(inputSchema, true); + return toJSONSchema(strictSchema, params); + } else return toJSONSchema(schema, params); + } + if (isZodSchemaV3(schema)) return zodToJsonSchema_zodToJsonSchema(schema); + return schema; } -function serializeGeneration(generation) { - const serializedValue = { text: generation.text }; - if (generation.message !== void 0) serializedValue.message = generation.message.toDict(); - return serializedValue; +/** +* Validates if a JSON schema validates only strings. May return false negatives in some edge cases +* (like recursive or unresolvable refs). +* +* @param schema - The schema to validate. +* @returns `true` if the schema validates only strings, `false` otherwise. +*/ +function validatesOnlyStrings(schema) { + if (!schema || typeof schema !== "object" || Object.keys(schema).length === 0 || Array.isArray(schema)) return false; + if ("type" in schema) { + if (typeof schema.type === "string") return schema.type === "string"; + if (Array.isArray(schema.type)) return schema.type.every((t) => t === "string"); + return false; + } + if ("enum" in schema) return Array.isArray(schema.enum) && schema.enum.length > 0 && schema.enum.every((val) => typeof val === "string"); + if ("const" in schema) return typeof schema.const === "string"; + if ("allOf" in schema && Array.isArray(schema.allOf)) return schema.allOf.some((subschema) => validatesOnlyStrings(subschema)); + if ("anyOf" in schema && Array.isArray(schema.anyOf) || "oneOf" in schema && Array.isArray(schema.oneOf)) { + const subschemas = "anyOf" in schema ? schema.anyOf : schema.oneOf; + return subschemas.length > 0 && subschemas.every((subschema) => validatesOnlyStrings(subschema)); + } + if ("not" in schema) return false; + if ("$ref" in schema && typeof schema.$ref === "string") { + const ref = schema.$ref; + const resolved = dereference(schema); + if (resolved[ref]) return validatesOnlyStrings(resolved[ref]); + return false; + } + return false; +} + +//#endregion + +//# sourceMappingURL=json_schema.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/utils.js +//#region src/runnables/utils.ts +function isRunnableInterface(thing) { + return thing ? thing.lc_runnable : false; } /** -* Base class for all caches. All caches should extend this class. +* Utility to filter the root event in the streamEvents implementation. +* This is simply binding the arguments to the namespace to make save on +* a bit of typing in the streamEvents implementation. +* +* TODO: Refactor and remove. */ -var caches_BaseCache = class { - keyEncoder = defaultHashKeyEncoder; - /** - * Sets a custom key encoder function for the cache. - * This function should take a prompt and an LLM key and return a string - * that will be used as the cache key. - * @param keyEncoderFn The custom key encoder function. - */ - makeDefaultKeyEncoder(keyEncoderFn) { - this.keyEncoder = keyEncoderFn; +var _RootEventFilter = class { + includeNames; + includeTypes; + includeTags; + excludeNames; + excludeTypes; + excludeTags; + constructor(fields) { + this.includeNames = fields.includeNames; + this.includeTypes = fields.includeTypes; + this.includeTags = fields.includeTags; + this.excludeNames = fields.excludeNames; + this.excludeTypes = fields.excludeTypes; + this.excludeTags = fields.excludeTags; + } + includeEvent(event, rootType) { + let include = this.includeNames === void 0 && this.includeTypes === void 0 && this.includeTags === void 0; + const eventTags = event.tags ?? []; + if (this.includeNames !== void 0) include = include || this.includeNames.includes(event.name); + if (this.includeTypes !== void 0) include = include || this.includeTypes.includes(rootType); + if (this.includeTags !== void 0) include = include || eventTags.some((tag) => this.includeTags?.includes(tag)); + if (this.excludeNames !== void 0) include = include && !this.excludeNames.includes(event.name); + if (this.excludeTypes !== void 0) include = include && !this.excludeTypes.includes(rootType); + if (this.excludeTags !== void 0) include = include && eventTags.every((tag) => !this.excludeTags?.includes(tag)); + return include; } }; -const GLOBAL_MAP = /* @__PURE__ */ new Map(); +const toBase64Url = (str) => { + const encoded = btoa(str); + return encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); +}; + +//#endregion + +//# sourceMappingURL=utils.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/graph_mermaid.js + + +//#region src/runnables/graph_mermaid.ts +function _escapeNodeLabel(nodeLabel) { + return nodeLabel.replace(/[^a-zA-Z-_0-9]/g, "_"); +} +const MARKDOWN_SPECIAL_CHARS = [ + "*", + "_", + "`" +]; +function _generateMermaidGraphStyles(nodeColors) { + let styles = ""; + for (const [className, color] of Object.entries(nodeColors)) styles += `\tclassDef ${className} ${color};\n`; + return styles; +} /** -* A cache for storing LLM generations that stores data in memory. +* Draws a Mermaid graph using the provided graph data */ -var InMemoryCache = class InMemoryCache extends caches_BaseCache { - cache; - constructor(map) { - super(); - this.cache = map ?? /* @__PURE__ */ new Map(); +function drawMermaid(nodes, edges, config) { + const { firstNode, lastNode, nodeColors, withStyles = true, curveStyle = "linear", wrapLabelNWords = 9 } = config ?? {}; + let mermaidGraph = withStyles ? `%%{init: {'flowchart': {'curve': '${curveStyle}'}}}%%\ngraph TD;\n` : "graph TD;\n"; + if (withStyles) { + const defaultClassLabel = "default"; + const formatDict = { [defaultClassLabel]: "{0}({1})" }; + if (firstNode !== void 0) formatDict[firstNode] = "{0}([{1}]):::first"; + if (lastNode !== void 0) formatDict[lastNode] = "{0}([{1}]):::last"; + for (const [key, node] of Object.entries(nodes)) { + const nodeName = node.name.split(":").pop() ?? ""; + const label = MARKDOWN_SPECIAL_CHARS.some((char) => nodeName.startsWith(char) && nodeName.endsWith(char)) ? `

${nodeName}

` : nodeName; + let finalLabel = label; + if (Object.keys(node.metadata ?? {}).length) finalLabel += `
${Object.entries(node.metadata ?? {}).map(([k, v]) => `${k} = ${v}`).join("\n")}`; + const nodeLabel = (formatDict[key] ?? formatDict[defaultClassLabel]).replace("{0}", _escapeNodeLabel(key)).replace("{1}", finalLabel); + mermaidGraph += `\t${nodeLabel}\n`; + } + } + const edgeGroups = {}; + for (const edge of edges) { + const srcParts = edge.source.split(":"); + const tgtParts = edge.target.split(":"); + const commonPrefix = srcParts.filter((src, i) => src === tgtParts[i]).join(":"); + if (!edgeGroups[commonPrefix]) edgeGroups[commonPrefix] = []; + edgeGroups[commonPrefix].push(edge); + } + const seenSubgraphs = /* @__PURE__ */ new Set(); + function sortPrefixesByDepth(prefixes) { + return [...prefixes].sort((a, b) => { + return a.split(":").length - b.split(":").length; + }); + } + function addSubgraph(edges$1, prefix) { + const selfLoop = edges$1.length === 1 && edges$1[0].source === edges$1[0].target; + if (prefix && !selfLoop) { + const subgraph = prefix.split(":").pop(); + if (seenSubgraphs.has(prefix)) throw new Error(`Found duplicate subgraph '${subgraph}' at '${prefix} -- this likely means that you're reusing a subgraph node with the same name. Please adjust your graph to have subgraph nodes with unique names.`); + seenSubgraphs.add(prefix); + mermaidGraph += `\tsubgraph ${subgraph}\n`; + } + const nestedPrefixes = sortPrefixesByDepth(Object.keys(edgeGroups).filter((nestedPrefix) => nestedPrefix.startsWith(`${prefix}:`) && nestedPrefix !== prefix && nestedPrefix.split(":").length === prefix.split(":").length + 1)); + for (const nestedPrefix of nestedPrefixes) addSubgraph(edgeGroups[nestedPrefix], nestedPrefix); + for (const edge of edges$1) { + const { source, target, data, conditional } = edge; + let edgeLabel = ""; + if (data !== void 0) { + let edgeData = data; + const words = edgeData.split(" "); + if (words.length > wrapLabelNWords) edgeData = Array.from({ length: Math.ceil(words.length / wrapLabelNWords) }, (_, i) => words.slice(i * wrapLabelNWords, (i + 1) * wrapLabelNWords).join(" ")).join(" 
 "); + edgeLabel = conditional ? ` -.  ${edgeData}  .-> ` : ` --  ${edgeData}  --> `; + } else edgeLabel = conditional ? " -.-> " : " --> "; + mermaidGraph += `\t${_escapeNodeLabel(source)}${edgeLabel}${_escapeNodeLabel(target)};\n`; + } + if (prefix && !selfLoop) mermaidGraph += " end\n"; + } + addSubgraph(edgeGroups[""] ?? [], ""); + for (const prefix in edgeGroups) if (!prefix.includes(":") && prefix !== "") addSubgraph(edgeGroups[prefix], prefix); + if (withStyles) mermaidGraph += _generateMermaidGraphStyles(nodeColors ?? {}); + return mermaidGraph; +} +/** +* Renders Mermaid graph using the Mermaid.INK API. +* +* @example +* ```javascript +* const image = await drawMermaidImage(mermaidSyntax, { +* backgroundColor: "white", +* imageType: "png", +* }); +* fs.writeFileSync("image.png", image); +* ``` +* +* @param mermaidSyntax - The Mermaid syntax to render. +* @param config - The configuration for the image. +* @returns The image as a Blob. +*/ +async function drawMermaidImage(mermaidSyntax, config) { + let backgroundColor = config?.backgroundColor ?? "white"; + const imageType = config?.imageType ?? "png"; + const mermaidSyntaxEncoded = toBase64Url(mermaidSyntax); + if (backgroundColor !== void 0) { + const hexColorPattern = /^#(?:[0-9a-fA-F]{3}){1,2}$/; + if (!hexColorPattern.test(backgroundColor)) backgroundColor = `!${backgroundColor}`; + } + const imageUrl = `https://mermaid.ink/img/${mermaidSyntaxEncoded}?bgColor=${backgroundColor}&type=${imageType}`; + const res = await fetch(imageUrl); + if (!res.ok) throw new Error([ + `Failed to render the graph using the Mermaid.INK API.`, + `Status code: ${res.status}`, + `Status text: ${res.statusText}` + ].join("\n")); + const content = await res.blob(); + return content; +} + +//#endregion + +//# sourceMappingURL=graph_mermaid.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/graph.js + + + + + + +//#region src/runnables/graph.ts +var graph_exports = {}; +__export(graph_exports, { Graph: () => Graph }); +function nodeDataStr(id, data) { + if (id !== void 0 && !wrapper_validate(id)) return id; + else if (isRunnableInterface(data)) try { + let dataStr = data.getName(); + dataStr = dataStr.startsWith("Runnable") ? dataStr.slice(8) : dataStr; + return dataStr; + } catch { + return data.getName(); + } + else return data.name ?? "UnknownSchema"; +} +function nodeDataJson(node) { + if (isRunnableInterface(node.data)) return { + type: "runnable", + data: { + id: node.data.lc_id, + name: node.data.getName() + } + }; + else return { + type: "schema", + data: { + ...toJsonSchema(node.data.schema), + title: node.data.name + } + }; +} +var Graph = class Graph { + nodes = {}; + edges = []; + constructor(params) { + this.nodes = params?.nodes ?? this.nodes; + this.edges = params?.edges ?? this.edges; + } + toJSON() { + const stableNodeIds = {}; + Object.values(this.nodes).forEach((node, i) => { + stableNodeIds[node.id] = wrapper_validate(node.id) ? i : node.id; + }); + return { + nodes: Object.values(this.nodes).map((node) => ({ + id: stableNodeIds[node.id], + ...nodeDataJson(node) + })), + edges: this.edges.map((edge) => { + const item = { + source: stableNodeIds[edge.source], + target: stableNodeIds[edge.target] + }; + if (typeof edge.data !== "undefined") item.data = edge.data; + if (typeof edge.conditional !== "undefined") item.conditional = edge.conditional; + return item; + }) + }; + } + addNode(data, id, metadata) { + if (id !== void 0 && this.nodes[id] !== void 0) throw new Error(`Node with id ${id} already exists`); + const nodeId = id ?? v4(); + const node = { + id: nodeId, + data, + name: nodeDataStr(id, data), + metadata + }; + this.nodes[nodeId] = node; + return node; + } + removeNode(node) { + delete this.nodes[node.id]; + this.edges = this.edges.filter((edge) => edge.source !== node.id && edge.target !== node.id); + } + addEdge(source, target, data, conditional) { + if (this.nodes[source.id] === void 0) throw new Error(`Source node ${source.id} not in graph`); + if (this.nodes[target.id] === void 0) throw new Error(`Target node ${target.id} not in graph`); + const edge = { + source: source.id, + target: target.id, + data, + conditional + }; + this.edges.push(edge); + return edge; + } + firstNode() { + return _firstNode(this); + } + lastNode() { + return _lastNode(this); } /** - * Retrieves data from the cache using a prompt and an LLM key. If the - * data is not found, it returns null. - * @param prompt The prompt used to find the data. - * @param llmKey The LLM key used to find the data. - * @returns The data corresponding to the prompt and LLM key, or null if not found. + * Add all nodes and edges from another graph. + * Note this doesn't check for duplicates, nor does it connect the graphs. */ - lookup(prompt, llmKey) { - return Promise.resolve(this.cache.get(this.keyEncoder(prompt, llmKey)) ?? null); + extend(graph, prefix = "") { + let finalPrefix = prefix; + const nodeIds = Object.values(graph.nodes).map((node) => node.id); + if (nodeIds.every(wrapper_validate)) finalPrefix = ""; + const prefixed = (id) => { + return finalPrefix ? `${finalPrefix}:${id}` : id; + }; + Object.entries(graph.nodes).forEach(([key, value]) => { + this.nodes[prefixed(key)] = { + ...value, + id: prefixed(key) + }; + }); + const newEdges = graph.edges.map((edge) => { + return { + ...edge, + source: prefixed(edge.source), + target: prefixed(edge.target) + }; + }); + this.edges = [...this.edges, ...newEdges]; + const first = graph.firstNode(); + const last = graph.lastNode(); + return [first ? { + id: prefixed(first.id), + data: first.data + } : void 0, last ? { + id: prefixed(last.id), + data: last.data + } : void 0]; + } + trimFirstNode() { + const firstNode = this.firstNode(); + if (firstNode && _firstNode(this, [firstNode.id])) this.removeNode(firstNode); + } + trimLastNode() { + const lastNode = this.lastNode(); + if (lastNode && _lastNode(this, [lastNode.id])) this.removeNode(lastNode); } /** - * Updates the cache with new data using a prompt and an LLM key. - * @param prompt The prompt used to store the data. - * @param llmKey The LLM key used to store the data. - * @param value The data to be stored. + * Return a new graph with all nodes re-identified, + * using their unique, readable names where possible. */ - async update(prompt, llmKey, value) { - this.cache.set(this.keyEncoder(prompt, llmKey), value); + reid() { + const nodeLabels = Object.fromEntries(Object.values(this.nodes).map((node) => [node.id, node.name])); + const nodeLabelCounts = /* @__PURE__ */ new Map(); + Object.values(nodeLabels).forEach((label) => { + nodeLabelCounts.set(label, (nodeLabelCounts.get(label) || 0) + 1); + }); + const getNodeId = (nodeId) => { + const label = nodeLabels[nodeId]; + if (wrapper_validate(nodeId) && nodeLabelCounts.get(label) === 1) return label; + else return nodeId; + }; + return new Graph({ + nodes: Object.fromEntries(Object.entries(this.nodes).map(([id, node]) => [getNodeId(id), { + ...node, + id: getNodeId(id) + }])), + edges: this.edges.map((edge) => ({ + ...edge, + source: getNodeId(edge.source), + target: getNodeId(edge.target) + })) + }); + } + drawMermaid(params) { + const { withStyles, curveStyle, nodeColors = { + default: "fill:#f2f0ff,line-height:1.2", + first: "fill-opacity:0", + last: "fill:#bfb6fc" + }, wrapLabelNWords } = params ?? {}; + const graph = this.reid(); + const firstNode = graph.firstNode(); + const lastNode = graph.lastNode(); + return drawMermaid(graph.nodes, graph.edges, { + firstNode: firstNode?.id, + lastNode: lastNode?.id, + withStyles, + curveStyle, + nodeColors, + wrapLabelNWords + }); } - /** - * Returns a global instance of InMemoryCache using a predefined global - * map as the initial cache. - * @returns A global instance of InMemoryCache. - */ - static global() { - return new InMemoryCache(GLOBAL_MAP); + async drawMermaidPng(params) { + const mermaidSyntax = this.drawMermaid(params); + return drawMermaidImage(mermaidSyntax, { backgroundColor: params?.backgroundColor }); } }; - -//#endregion - -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/document_loaders/base.js - - -//#region src/document_loaders/base.ts -var document_loaders_base_base_exports = {}; -__export(document_loaders_base_base_exports, { BaseDocumentLoader: () => BaseDocumentLoader }); /** -* Abstract class that provides a default implementation for the -* loadAndSplit() method from the DocumentLoader interface. The load() -* method is left abstract and needs to be implemented by subclasses. +* Find the single node that is not a target of any edge. +* Exclude nodes/sources with ids in the exclude list. +* If there is no such node, or there are multiple, return undefined. +* When drawing the graph, this node would be the origin. */ -var BaseDocumentLoader = class {}; +function _firstNode(graph, exclude = []) { + const targets = new Set(graph.edges.filter((edge) => !exclude.includes(edge.source)).map((edge) => edge.target)); + const found = []; + for (const node of Object.values(graph.nodes)) if (!exclude.includes(node.id) && !targets.has(node.id)) found.push(node); + return found.length === 1 ? found[0] : void 0; +} +/** +* Find the single node that is not a source of any edge. +* Exclude nodes/targets with ids in the exclude list. +* If there is no such node, or there are multiple, return undefined. +* When drawing the graph, this node would be the destination. +*/ +function _lastNode(graph, exclude = []) { + const sources = new Set(graph.edges.filter((edge) => !exclude.includes(edge.target)).map((edge) => edge.source)); + const found = []; + for (const node of Object.values(graph.nodes)) if (!exclude.includes(node.id) && !sources.has(node.id)) found.push(node); + return found.length === 1 ? found[0] : void 0; +} //#endregion -//# sourceMappingURL=base.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/document_loaders/langsmith.js +//# sourceMappingURL=graph.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tracers/event_stream.js -//#region src/document_loaders/langsmith.ts -var langsmith_exports = {}; -__export(langsmith_exports, { LangSmithLoader: () => LangSmithLoader }); + +//#region src/tracers/event_stream.ts +function assignName({ name, serialized }) { + if (name !== void 0) return name; + if (serialized?.name !== void 0) return serialized.name; + else if (serialized?.id !== void 0 && Array.isArray(serialized?.id)) return serialized.id[serialized.id.length - 1]; + return "Unnamed"; +} +const isStreamEventsHandler = (handler) => handler.name === "event_stream_tracer"; /** -* Document loader integration with LangSmith. -* -* ## [Constructor args](https://api.js.langchain.com/interfaces/_langchain_core.document_loaders_langsmith.LangSmithLoaderFields.html) -* -*
-* Load -* -* ```typescript -* import { LangSmithLoader } from '@langchain/core/document_loaders/langsmith'; -* import { Client } from 'langsmith'; -* -* const langSmithClient = new Client({ -* apiKey: process.env.LANGSMITH_API_KEY, -* }) -* -* const loader = new LangSmithLoader({ -* datasetId: "9a3b36f7-b308-40a5-9b46-6613853b6330", -* limit: 1, -* }); -* -* const docs = await loader.load(); -* ``` -* -* ```txt -* [ -* { -* pageContent: '{\n "input_key_str": "string",\n "input_key_bool": true\n}', -* metadata: { -* id: '8523d9e9-c123-4b23-9b46-21021nds289e', -* created_at: '2024-08-19T17:09:14.806441+00:00', -* modified_at: '2024-08-19T17:09:14.806441+00:00', -* name: '#8517 @ brace-test-dataset', -* dataset_id: '9a3b36f7-b308-40a5-9b46-6613853b6330', -* source_run_id: null, -* metadata: [Object], -* inputs: [Object], -* outputs: [Object] -* } -* } -* ] -* ``` -*
+* Class that extends the `BaseTracer` class from the +* `langchain.callbacks.tracers.base` module. It represents a callback +* handler that logs the execution of runs and emits `RunLog` instances to a +* `RunLogStream`. */ -var LangSmithLoader = class extends BaseDocumentLoader { - datasetId; - datasetName; - exampleIds; - asOf; - splits; - inlineS3Urls; - offset; - limit; - metadata; - filter; - contentKey; - formatContent; - client; +var EventStreamCallbackHandler = class extends BaseTracer { + autoClose = true; + includeNames; + includeTypes; + includeTags; + excludeNames; + excludeTypes; + excludeTags; + runInfoMap = /* @__PURE__ */ new Map(); + tappedPromises = /* @__PURE__ */ new Map(); + transformStream; + writer; + receiveStream; + readableStreamClosed = false; + name = "event_stream_tracer"; + lc_prefer_streaming = true; constructor(fields) { - super(); - if (fields.client && fields.clientConfig) throw new Error("client and clientConfig cannot both be provided."); - this.client = fields.client ?? new Client(fields?.clientConfig); - this.contentKey = fields.contentKey ? fields.contentKey.split(".") : []; - this.formatContent = fields.formatContent ?? _stringify; - this.datasetId = fields.datasetId; - this.datasetName = fields.datasetName; - this.exampleIds = fields.exampleIds; - this.asOf = fields.asOf; - this.splits = fields.splits; - this.inlineS3Urls = fields.inlineS3Urls; - this.offset = fields.offset; - this.limit = fields.limit; - this.metadata = fields.metadata; - this.filter = fields.filter; + super({ + _awaitHandler: true, + ...fields + }); + this.autoClose = fields?.autoClose ?? true; + this.includeNames = fields?.includeNames; + this.includeTypes = fields?.includeTypes; + this.includeTags = fields?.includeTags; + this.excludeNames = fields?.excludeNames; + this.excludeTypes = fields?.excludeTypes; + this.excludeTags = fields?.excludeTags; + this.transformStream = new TransformStream({ flush: () => { + this.readableStreamClosed = true; + } }); + this.writer = this.transformStream.writable.getWriter(); + this.receiveStream = IterableReadableStream.fromReadableStream(this.transformStream.readable); } - async load() { - const documents = []; - for await (const example of this.client.listExamples({ - datasetId: this.datasetId, - datasetName: this.datasetName, - exampleIds: this.exampleIds, - asOf: this.asOf, - splits: this.splits, - inlineS3Urls: this.inlineS3Urls, - offset: this.offset, - limit: this.limit, - metadata: this.metadata, - filter: this.filter - })) { - let content = example.inputs; - for (const key of this.contentKey) content = content[key]; - const contentStr = this.formatContent(content); - const metadata = example; - ["created_at", "modified_at"].forEach((k) => { - if (k in metadata) { - if (typeof metadata[k] === "object") metadata[k] = metadata[k].toString(); - } + [Symbol.asyncIterator]() { + return this.receiveStream; + } + async persistRun(_run) {} + _includeRun(run) { + const runTags = run.tags ?? []; + let include = this.includeNames === void 0 && this.includeTags === void 0 && this.includeTypes === void 0; + if (this.includeNames !== void 0) include = include || this.includeNames.includes(run.name); + if (this.includeTypes !== void 0) include = include || this.includeTypes.includes(run.runType); + if (this.includeTags !== void 0) include = include || runTags.find((tag) => this.includeTags?.includes(tag)) !== void 0; + if (this.excludeNames !== void 0) include = include && !this.excludeNames.includes(run.name); + if (this.excludeTypes !== void 0) include = include && !this.excludeTypes.includes(run.runType); + if (this.excludeTags !== void 0) include = include && runTags.every((tag) => !this.excludeTags?.includes(tag)); + return include; + } + async *tapOutputIterable(runId, outputStream) { + const firstChunk = await outputStream.next(); + if (firstChunk.done) return; + const runInfo = this.runInfoMap.get(runId); + if (runInfo === void 0) { + yield firstChunk.value; + return; + } + function _formatOutputChunk(eventType, data) { + if (eventType === "llm" && typeof data === "string") return new GenerationChunk({ text: data }); + return data; + } + let tappedPromise = this.tappedPromises.get(runId); + if (tappedPromise === void 0) { + let tappedPromiseResolver; + tappedPromise = new Promise((resolve) => { + tappedPromiseResolver = resolve; }); - documents.push({ - pageContent: contentStr, - metadata + this.tappedPromises.set(runId, tappedPromise); + try { + const event = { + event: `on_${runInfo.runType}_stream`, + run_id: runId, + name: runInfo.name, + tags: runInfo.tags, + metadata: runInfo.metadata, + data: {} + }; + await this.send({ + ...event, + data: { chunk: _formatOutputChunk(runInfo.runType, firstChunk.value) } + }, runInfo); + yield firstChunk.value; + for await (const chunk of outputStream) { + if (runInfo.runType !== "tool" && runInfo.runType !== "retriever") await this.send({ + ...event, + data: { chunk: _formatOutputChunk(runInfo.runType, chunk) } + }, runInfo); + yield chunk; + } + } finally { + tappedPromiseResolver?.(); + } + } else { + yield firstChunk.value; + for await (const chunk of outputStream) yield chunk; + } + } + async send(payload, run) { + if (this.readableStreamClosed) return; + if (this._includeRun(run)) await this.writer.write(payload); + } + async sendEndEvent(payload, run) { + const tappedPromise = this.tappedPromises.get(payload.run_id); + if (tappedPromise !== void 0) tappedPromise.then(() => { + this.send(payload, run); + }); + else await this.send(payload, run); + } + async onLLMStart(run) { + const runName = assignName(run); + const runType = run.inputs.messages !== void 0 ? "chat_model" : "llm"; + const runInfo = { + tags: run.tags ?? [], + metadata: run.extra?.metadata ?? {}, + name: runName, + runType, + inputs: run.inputs + }; + this.runInfoMap.set(run.id, runInfo); + const eventName = `on_${runType}_start`; + await this.send({ + event: eventName, + data: { input: run.inputs }, + name: runName, + tags: run.tags ?? [], + run_id: run.id, + metadata: run.extra?.metadata ?? {} + }, runInfo); + } + async onLLMNewToken(run, token, kwargs) { + const runInfo = this.runInfoMap.get(run.id); + let chunk; + let eventName; + if (runInfo === void 0) throw new Error(`onLLMNewToken: Run ID ${run.id} not found in run map.`); + if (this.runInfoMap.size === 1) return; + if (runInfo.runType === "chat_model") { + eventName = "on_chat_model_stream"; + if (kwargs?.chunk === void 0) chunk = new AIMessageChunk({ + content: token, + id: `run-${run.id}` }); + else chunk = kwargs.chunk.message; + } else if (runInfo.runType === "llm") { + eventName = "on_llm_stream"; + if (kwargs?.chunk === void 0) chunk = new GenerationChunk({ text: token }); + else chunk = kwargs.chunk; + } else throw new Error(`Unexpected run type ${runInfo.runType}`); + await this.send({ + event: eventName, + data: { chunk }, + run_id: run.id, + name: runInfo.name, + tags: runInfo.tags, + metadata: runInfo.metadata + }, runInfo); + } + async onLLMEnd(run) { + const runInfo = this.runInfoMap.get(run.id); + this.runInfoMap.delete(run.id); + let eventName; + if (runInfo === void 0) throw new Error(`onLLMEnd: Run ID ${run.id} not found in run map.`); + const generations = run.outputs?.generations; + let output; + if (runInfo.runType === "chat_model") { + for (const generation of generations ?? []) { + if (output !== void 0) break; + output = generation[0]?.message; + } + eventName = "on_chat_model_end"; + } else if (runInfo.runType === "llm") { + output = { + generations: generations?.map((generation) => { + return generation.map((chunk) => { + return { + text: chunk.text, + generationInfo: chunk.generationInfo + }; + }); + }), + llmOutput: run.outputs?.llmOutput ?? {} + }; + eventName = "on_llm_end"; + } else throw new Error(`onLLMEnd: Unexpected run type: ${runInfo.runType}`); + await this.sendEndEvent({ + event: eventName, + data: { + output, + input: runInfo.inputs + }, + run_id: run.id, + name: runInfo.name, + tags: runInfo.tags, + metadata: runInfo.metadata + }, runInfo); + } + async onChainStart(run) { + const runName = assignName(run); + const runType = run.run_type ?? "chain"; + const runInfo = { + tags: run.tags ?? [], + metadata: run.extra?.metadata ?? {}, + name: runName, + runType: run.run_type + }; + let eventData = {}; + if (run.inputs.input === "" && Object.keys(run.inputs).length === 1) { + eventData = {}; + runInfo.inputs = {}; + } else if (run.inputs.input !== void 0) { + eventData.input = run.inputs.input; + runInfo.inputs = run.inputs.input; + } else { + eventData.input = run.inputs; + runInfo.inputs = run.inputs; } - return documents; + this.runInfoMap.set(run.id, runInfo); + await this.send({ + event: `on_${runType}_start`, + data: eventData, + name: runName, + tags: run.tags ?? [], + run_id: run.id, + metadata: run.extra?.metadata ?? {} + }, runInfo); } -}; -function _stringify(x) { - if (typeof x === "string") return x; - else try { - return JSON.stringify(x, null, 2); - } catch { - return String(x); + async onChainEnd(run) { + const runInfo = this.runInfoMap.get(run.id); + this.runInfoMap.delete(run.id); + if (runInfo === void 0) throw new Error(`onChainEnd: Run ID ${run.id} not found in run map.`); + const eventName = `on_${run.run_type}_end`; + const inputs = run.inputs ?? runInfo.inputs ?? {}; + const outputs = run.outputs?.output ?? run.outputs; + const data = { + output: outputs, + input: inputs + }; + if (inputs.input && Object.keys(inputs).length === 1) { + data.input = inputs.input; + runInfo.inputs = inputs.input; + } + await this.sendEndEvent({ + event: eventName, + data, + run_id: run.id, + name: runInfo.name, + tags: runInfo.tags, + metadata: runInfo.metadata ?? {} + }, runInfo); } -} - -//#endregion - -//# sourceMappingURL=langsmith.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/documents/document.js -//#region src/documents/document.ts -/** -* Interface for interacting with a document. -*/ -var Document = class { - pageContent; - metadata; - /** - * An optional identifier for the document. - * - * Ideally this should be unique across the document collection and formatted - * as a UUID, but this will not be enforced. - */ - id; - constructor(fields) { - this.pageContent = fields.pageContent !== void 0 ? fields.pageContent.toString() : ""; - this.metadata = fields.metadata ?? {}; - this.id = fields.id; + async onToolStart(run) { + const runName = assignName(run); + const runInfo = { + tags: run.tags ?? [], + metadata: run.extra?.metadata ?? {}, + name: runName, + runType: "tool", + inputs: run.inputs ?? {} + }; + this.runInfoMap.set(run.id, runInfo); + await this.send({ + event: "on_tool_start", + data: { input: run.inputs ?? {} }, + name: runName, + run_id: run.id, + tags: run.tags ?? [], + metadata: run.extra?.metadata ?? {} + }, runInfo); + } + async onToolEnd(run) { + const runInfo = this.runInfoMap.get(run.id); + this.runInfoMap.delete(run.id); + if (runInfo === void 0) throw new Error(`onToolEnd: Run ID ${run.id} not found in run map.`); + if (runInfo.inputs === void 0) throw new Error(`onToolEnd: Run ID ${run.id} is a tool call, and is expected to have traced inputs.`); + const output = run.outputs?.output === void 0 ? run.outputs : run.outputs.output; + await this.sendEndEvent({ + event: "on_tool_end", + data: { + output, + input: runInfo.inputs + }, + run_id: run.id, + name: runInfo.name, + tags: runInfo.tags, + metadata: runInfo.metadata + }, runInfo); + } + async onRetrieverStart(run) { + const runName = assignName(run); + const runType = "retriever"; + const runInfo = { + tags: run.tags ?? [], + metadata: run.extra?.metadata ?? {}, + name: runName, + runType, + inputs: { query: run.inputs.query } + }; + this.runInfoMap.set(run.id, runInfo); + await this.send({ + event: "on_retriever_start", + data: { input: { query: run.inputs.query } }, + name: runName, + tags: run.tags ?? [], + run_id: run.id, + metadata: run.extra?.metadata ?? {} + }, runInfo); + } + async onRetrieverEnd(run) { + const runInfo = this.runInfoMap.get(run.id); + this.runInfoMap.delete(run.id); + if (runInfo === void 0) throw new Error(`onRetrieverEnd: Run ID ${run.id} not found in run map.`); + await this.sendEndEvent({ + event: "on_retriever_end", + data: { + output: run.outputs?.documents ?? run.outputs, + input: runInfo.inputs + }, + run_id: run.id, + name: runInfo.name, + tags: runInfo.tags, + metadata: runInfo.metadata + }, runInfo); + } + async handleCustomEvent(eventName, data, runId) { + const runInfo = this.runInfoMap.get(runId); + if (runInfo === void 0) throw new Error(`handleCustomEvent: Run ID ${runId} not found in run map.`); + await this.send({ + event: "on_custom_event", + run_id: runId, + name: eventName, + tags: runInfo.tags, + metadata: runInfo.metadata, + data + }, runInfo); + } + async finish() { + const pendingPromises = [...this.tappedPromises.values()]; + Promise.all(pendingPromises).finally(() => { + this.writer.close(); + }); } }; //#endregion -//# sourceMappingURL=document.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/documents/transformers.js +//# sourceMappingURL=event_stream.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tracers/root_listener.js -//#region src/documents/transformers.ts -/** -* Abstract base class for document transformation systems. -* -* A document transformation system takes an array of Documents and returns an -* array of transformed Documents. These arrays do not necessarily have to have -* the same length. -* -* One example of this is a text splitter that splits a large document into -* many smaller documents. -*/ -var BaseDocumentTransformer = class extends Runnable { - lc_namespace = [ - "langchain_core", - "documents", - "transformers" - ]; +//#region src/tracers/root_listener.ts +var RootListenersTracer = class extends BaseTracer { + name = "RootListenersTracer"; + /** The Run's ID. Type UUID */ + rootId; + config; + argOnStart; + argOnEnd; + argOnError; + constructor({ config, onStart, onEnd, onError }) { + super({ _awaitHandler: true }); + this.config = config; + this.argOnStart = onStart; + this.argOnEnd = onEnd; + this.argOnError = onError; + } /** - * Method to invoke the document transformation. This method calls the - * transformDocuments method with the provided input. - * @param input The input documents to be transformed. - * @param _options Optional configuration object to customize the behavior of callbacks. - * @returns A Promise that resolves to the transformed documents. + * This is a legacy method only called once for an entire run tree + * therefore not useful here + * @param {Run} _ Not used */ - invoke(input, _options) { - return this.transformDocuments(input); + persistRun(_) { + return Promise.resolve(); } -}; -/** -* Class for document transformers that return exactly one transformed document -* for each input document. -*/ -var MappingDocumentTransformer = class extends BaseDocumentTransformer { - async transformDocuments(documents) { - const newDocuments = []; - for (const document of documents) { - const transformedDocument = await this._transformDocument(document); - newDocuments.push(transformedDocument); - } - return newDocuments; + async onRunCreate(run) { + if (this.rootId) return; + this.rootId = run.id; + if (this.argOnStart) await this.argOnStart(run, this.config); + } + async onRunUpdate(run) { + if (run.id !== this.rootId) return; + if (!run.error) { + if (this.argOnEnd) await this.argOnEnd(run, this.config); + } else if (this.argOnError) await this.argOnError(run, this.config); } }; //#endregion -//# sourceMappingURL=transformers.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/documents/index.js - - +//# sourceMappingURL=root_listener.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/wrappers.js -//#region src/documents/index.ts -var documents_exports = {}; -__export(documents_exports, { - BaseDocumentTransformer: () => BaseDocumentTransformer, - Document: () => Document, - MappingDocumentTransformer: () => MappingDocumentTransformer -}); +//#region src/runnables/wrappers.ts +function convertToHttpEventStream(stream) { + const encoder = new TextEncoder(); + const finalStream = new ReadableStream({ async start(controller) { + for await (const chunk of stream) controller.enqueue(encoder.encode(`event: data\ndata: ${JSON.stringify(chunk)}\n\n`)); + controller.enqueue(encoder.encode("event: end\n\n")); + controller.close(); + } }); + return IterableReadableStream.fromReadableStream(finalStream); +} //#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/base.js +//# sourceMappingURL=wrappers.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/iter.js -//#region src/example_selectors/base.ts -/** -* Base class for example selectors. -*/ -var BaseExampleSelector = class extends Serializable { - lc_namespace = [ - "langchain_core", - "example_selectors", - "base" - ]; -}; -//#endregion -//# sourceMappingURL=base.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/conditional.js -//#region src/example_selectors/conditional.ts -/** -* Abstract class that defines the interface for selecting a prompt for a -* given language model. -*/ -var BasePromptSelector = class { - /** - * Asynchronous version of `getPrompt` that also accepts an options object - * for partial variables. - * @param llm The language model for which to get a prompt. - * @param options Optional object for partial variables. - * @returns A Promise that resolves to a prompt template. - */ - async getPromptAsync(llm, options) { - const prompt = this.getPrompt(llm); - return prompt.partial(options?.partialVariables ?? {}); - } -}; -/** -* Concrete implementation of `BasePromptSelector` that selects a prompt -* based on a set of conditions. It has a default prompt that it returns -* if none of the conditions are met. -*/ -var ConditionalPromptSelector = class extends BasePromptSelector { - defaultPrompt; - conditionals; - constructor(default_prompt, conditionals = []) { - super(); - this.defaultPrompt = default_prompt; - this.conditionals = conditionals; - } - /** - * Method that selects a prompt based on a set of conditions. If none of - * the conditions are met, it returns the default prompt. - * @param llm The language model for which to get a prompt. - * @returns A prompt template. - */ - getPrompt(llm) { - for (const [condition, prompt] of this.conditionals) if (condition(llm)) return prompt; - return this.defaultPrompt; +//#region src/runnables/iter.ts +function isIterableIterator(thing) { + return typeof thing === "object" && thing !== null && typeof thing[Symbol.iterator] === "function" && typeof thing.next === "function"; +} +const isIterator = (x) => x != null && typeof x === "object" && "next" in x && typeof x.next === "function"; +function isAsyncIterable(thing) { + return typeof thing === "object" && thing !== null && typeof thing[Symbol.asyncIterator] === "function"; +} +function* consumeIteratorInContext(context, iter) { + while (true) { + const { value, done } = async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(context), iter.next.bind(iter), true); + if (done) break; + else yield value; } -}; -/** -* Type guard function that checks if a given language model is of type -* `BaseLLM`. -*/ -function isLLM(llm) { - return llm._modelType() === "base_llm"; } -/** -* Type guard function that checks if a given language model is of type -* `BaseChatModel`. -*/ -function isChatModel(llm) { - return llm._modelType() === "base_chat_model"; +async function* consumeAsyncIterableInContext(context, iter) { + const iterator = iter[Symbol.asyncIterator](); + while (true) { + const { value, done } = await async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(context), iterator.next.bind(iter), true); + if (done) break; + else yield value; + } } //#endregion -//# sourceMappingURL=conditional.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/length_based.js +//# sourceMappingURL=iter.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/base.js -//#region src/example_selectors/length_based.ts -/** -* Calculates the length of a text based on the number of words and lines. -*/ -function getLengthBased(text) { - return text.split(/\n| /).length; + + + + + + + + + + + + + + + + + + + +//#region src/runnables/base.ts +function base_coerceToDict(value, defaultKey) { + return value && !Array.isArray(value) && !(value instanceof Date) && typeof value === "object" ? value : { [defaultKey]: value }; } /** -* A specialized example selector that selects examples based on their -* length, ensuring that the total length of the selected examples does -* not exceed a specified maximum length. -* @example -* ```typescript -* const exampleSelector = new LengthBasedExampleSelector( -* [ -* { input: "happy", output: "sad" }, -* { input: "tall", output: "short" }, -* { input: "energetic", output: "lethargic" }, -* { input: "sunny", output: "gloomy" }, -* { input: "windy", output: "calm" }, -* ], -* { -* examplePrompt: new PromptTemplate({ -* inputVariables: ["input", "output"], -* template: "Input: {input}\nOutput: {output}", -* }), -* maxLength: 25, -* }, -* ); -* const dynamicPrompt = new FewShotPromptTemplate({ -* exampleSelector, -* examplePrompt: new PromptTemplate({ -* inputVariables: ["input", "output"], -* template: "Input: {input}\nOutput: {output}", -* }), -* prefix: "Give the antonym of every input", -* suffix: "Input: {adjective}\nOutput:", -* inputVariables: ["adjective"], -* }); -* console.log(dynamicPrompt.format({ adjective: "big" })); -* console.log( -* dynamicPrompt.format({ -* adjective: -* "big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else", -* }), -* ); -* ``` +* A Runnable is a generic unit of work that can be invoked, batched, streamed, and/or +* transformed. */ -var LengthBasedExampleSelector = class LengthBasedExampleSelector extends BaseExampleSelector { - examples = []; - examplePrompt; - getTextLength = getLengthBased; - maxLength = 2048; - exampleTextLengths = []; - constructor(data) { - super(data); - this.examplePrompt = data.examplePrompt; - this.maxLength = data.maxLength ?? 2048; - this.getTextLength = data.getTextLength ?? getLengthBased; +var Runnable = class extends Serializable { + lc_runnable = true; + name; + getName(suffix) { + const name = this.name ?? this.constructor.lc_name() ?? this.constructor.name; + return suffix ? `${name}${suffix}` : name; } /** - * Adds an example to the list of examples and calculates its length. - * @param example The example to be added. - * @returns Promise that resolves when the example has been added and its length calculated. + * Add retry logic to an existing runnable. + * @param fields.stopAfterAttempt The number of attempts to retry. + * @param fields.onFailedAttempt A function that is called when a retry fails. + * @returns A new RunnableRetry that, when invoked, will retry according to the parameters. */ - async addExample(example) { - this.examples.push(example); - const stringExample = await this.examplePrompt.format(example); - this.exampleTextLengths.push(this.getTextLength(stringExample)); + withRetry(fields) { + return new RunnableRetry({ + bound: this, + kwargs: {}, + config: {}, + maxAttemptNumber: fields?.stopAfterAttempt, + ...fields + }); + } + /** + * Bind config to a Runnable, returning a new Runnable. + * @param config New configuration parameters to attach to the new runnable. + * @returns A new RunnableBinding with a config matching what's passed. + */ + withConfig(config) { + return new RunnableBinding({ + bound: this, + config, + kwargs: {} + }); + } + /** + * Create a new runnable from the current one that will try invoking + * other passed fallback runnables if the initial invocation fails. + * @param fields.fallbacks Other runnables to call if the runnable errors. + * @returns A new RunnableWithFallbacks. + */ + withFallbacks(fields) { + const fallbacks = Array.isArray(fields) ? fields : fields.fallbacks; + return new RunnableWithFallbacks({ + runnable: this, + fallbacks + }); + } + _getOptionsList(options, length = 0) { + if (Array.isArray(options) && options.length !== length) throw new Error(`Passed "options" must be an array with the same length as the inputs, but got ${options.length} options for ${length} inputs`); + if (Array.isArray(options)) return options.map(ensureConfig); + if (length > 1 && !Array.isArray(options) && options.runId) { + console.warn("Provided runId will be used only for the first element of the batch."); + const subsequent = Object.fromEntries(Object.entries(options).filter(([key]) => key !== "runId")); + return Array.from({ length }, (_, i) => ensureConfig(i === 0 ? options : subsequent)); + } + return Array.from({ length }, () => ensureConfig(options)); + } + async batch(inputs, options, batchOptions) { + const configList = this._getOptionsList(options ?? {}, inputs.length); + const maxConcurrency = configList[0]?.maxConcurrency ?? batchOptions?.maxConcurrency; + const caller = new async_caller_AsyncCaller({ + maxConcurrency, + onFailedAttempt: (e) => { + throw e; + } + }); + const batchCalls = inputs.map((input, i) => caller.call(async () => { + try { + const result = await this.invoke(input, configList[i]); + return result; + } catch (e) { + if (batchOptions?.returnExceptions) return e; + throw e; + } + })); + return Promise.all(batchCalls); + } + /** + * Default streaming implementation. + * Subclasses should override this method if they support streaming output. + * @param input + * @param options + */ + async *_streamIterator(input, options) { + yield this.invoke(input, options); + } + /** + * Stream output in chunks. + * @param input + * @param options + * @returns A readable stream that is also an iterable. + */ + async stream(input, options) { + const config = ensureConfig(options); + const wrappedGenerator = new AsyncGeneratorWithSetup({ + generator: this._streamIterator(input, config), + config + }); + await wrappedGenerator.setup; + return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); + } + _separateRunnableConfigFromCallOptions(options) { + let runnableConfig; + if (options === void 0) runnableConfig = ensureConfig(options); + else runnableConfig = ensureConfig({ + callbacks: options.callbacks, + tags: options.tags, + metadata: options.metadata, + runName: options.runName, + configurable: options.configurable, + recursionLimit: options.recursionLimit, + maxConcurrency: options.maxConcurrency, + runId: options.runId, + timeout: options.timeout, + signal: options.signal + }); + const callOptions = { ...options }; + delete callOptions.callbacks; + delete callOptions.tags; + delete callOptions.metadata; + delete callOptions.runName; + delete callOptions.configurable; + delete callOptions.recursionLimit; + delete callOptions.maxConcurrency; + delete callOptions.runId; + delete callOptions.timeout; + delete callOptions.signal; + return [runnableConfig, callOptions]; + } + async _callWithConfig(func, input, options) { + const config = ensureConfig(options); + const callbackManager_ = await getCallbackManagerForConfig(config); + const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), config.runId, config?.runType, void 0, void 0, config?.runName ?? this.getName()); + delete config.runId; + let output; + try { + const promise = func.call(this, input, config, runManager); + output = await raceWithSignal(promise, options?.signal); + } catch (e) { + await runManager?.handleChainError(e); + throw e; + } + await runManager?.handleChainEnd(base_coerceToDict(output, "output")); + return output; + } + /** + * Internal method that handles batching and configuration for a runnable + * It takes a function, input values, and optional configuration, and + * returns a promise that resolves to the output values. + * @param func The function to be executed for each input value. + * @param input The input values to be processed. + * @param config Optional configuration for the function execution. + * @returns A promise that resolves to the output values. + */ + async _batchWithConfig(func, inputs, options, batchOptions) { + const optionsList = this._getOptionsList(options ?? {}, inputs.length); + const callbackManagers = await Promise.all(optionsList.map(getCallbackManagerForConfig)); + const runManagers = await Promise.all(callbackManagers.map(async (callbackManager, i) => { + const handleStartRes = await callbackManager?.handleChainStart(this.toJSON(), base_coerceToDict(inputs[i], "input"), optionsList[i].runId, optionsList[i].runType, void 0, void 0, optionsList[i].runName ?? this.getName()); + delete optionsList[i].runId; + return handleStartRes; + })); + let outputs; + try { + const promise = func.call(this, inputs, optionsList, runManagers, batchOptions); + outputs = await raceWithSignal(promise, optionsList?.[0]?.signal); + } catch (e) { + await Promise.all(runManagers.map((runManager) => runManager?.handleChainError(e))); + throw e; + } + await Promise.all(runManagers.map((runManager) => runManager?.handleChainEnd(base_coerceToDict(outputs, "output")))); + return outputs; + } + /** @internal */ + _concatOutputChunks(first, second) { + return concat(first, second); + } + /** + * Helper method to transform an Iterator of Input values into an Iterator of + * Output values, with callbacks. + * Use this to implement `stream()` or `transform()` in Runnable subclasses. + */ + async *_transformStreamWithConfig(inputGenerator, transformer, options) { + let finalInput; + let finalInputSupported = true; + let finalOutput; + let finalOutputSupported = true; + const config = ensureConfig(options); + const callbackManager_ = await getCallbackManagerForConfig(config); + const outerThis = this; + async function* wrapInputForTracing() { + for await (const chunk of inputGenerator) { + if (finalInputSupported) if (finalInput === void 0) finalInput = chunk; + else try { + finalInput = outerThis._concatOutputChunks(finalInput, chunk); + } catch { + finalInput = void 0; + finalInputSupported = false; + } + yield chunk; + } + } + let runManager; + try { + const pipe = await pipeGeneratorWithSetup(transformer.bind(this), wrapInputForTracing(), async () => callbackManager_?.handleChainStart(this.toJSON(), { input: "" }, config.runId, config.runType, void 0, void 0, config.runName ?? this.getName(), void 0, { lc_defers_inputs: true }), options?.signal, config); + delete config.runId; + runManager = pipe.setup; + const streamEventsHandler = runManager?.handlers.find(isStreamEventsHandler); + let iterator = pipe.output; + if (streamEventsHandler !== void 0 && runManager !== void 0) iterator = streamEventsHandler.tapOutputIterable(runManager.runId, iterator); + const streamLogHandler = runManager?.handlers.find(isLogStreamHandler); + if (streamLogHandler !== void 0 && runManager !== void 0) iterator = streamLogHandler.tapOutputIterable(runManager.runId, iterator); + for await (const chunk of iterator) { + yield chunk; + if (finalOutputSupported) if (finalOutput === void 0) finalOutput = chunk; + else try { + finalOutput = this._concatOutputChunks(finalOutput, chunk); + } catch { + finalOutput = void 0; + finalOutputSupported = false; + } + } + } catch (e) { + await runManager?.handleChainError(e, void 0, void 0, void 0, { inputs: base_coerceToDict(finalInput, "input") }); + throw e; + } + await runManager?.handleChainEnd(finalOutput ?? {}, void 0, void 0, void 0, { inputs: base_coerceToDict(finalInput, "input") }); } - /** - * Calculates the lengths of the examples. - * @param v Array of lengths of the examples. - * @param values Instance of LengthBasedExampleSelector. - * @returns Promise that resolves with an array of lengths of the examples. - */ - async calculateExampleTextLengths(v, values) { - if (v.length > 0) return v; - const { examples, examplePrompt } = values; - const stringExamples = await Promise.all(examples.map((eg) => examplePrompt.format(eg))); - return stringExamples.map((eg) => this.getTextLength(eg)); + getGraph(_) { + const graph = new Graph(); + const inputNode = graph.addNode({ + name: `${this.getName()}Input`, + schema: anyType() + }); + const runnableNode = graph.addNode(this); + const outputNode = graph.addNode({ + name: `${this.getName()}Output`, + schema: anyType() + }); + graph.addEdge(inputNode, runnableNode); + graph.addEdge(runnableNode, outputNode); + return graph; } /** - * Selects examples until the total length of the selected examples - * reaches the maxLength. - * @param inputVariables The input variables for the examples. - * @returns Promise that resolves with an array of selected examples. + * Create a new runnable sequence that runs each individual runnable in series, + * piping the output of one runnable into another runnable or runnable-like. + * @param coerceable A runnable, function, or object whose values are functions or runnables. + * @returns A new runnable sequence. */ - async selectExamples(inputVariables) { - const inputs = Object.values(inputVariables).join(" "); - let remainingLength = this.maxLength - this.getTextLength(inputs); - let i = 0; - const examples = []; - while (remainingLength > 0 && i < this.examples.length) { - const newLength = remainingLength - this.exampleTextLengths[i]; - if (newLength < 0) break; - else { - examples.push(this.examples[i]); - remainingLength = newLength; - } - i += 1; - } - return examples; + pipe(coerceable) { + return new RunnableSequence({ + first: this, + last: _coerceToRunnable(coerceable) + }); } /** - * Creates a new instance of LengthBasedExampleSelector and adds a list of - * examples to it. - * @param examples Array of examples to be added. - * @param args Input parameters for the LengthBasedExampleSelector. - * @returns Promise that resolves with a new instance of LengthBasedExampleSelector with the examples added. + * Pick keys from the dict output of this runnable. Returns a new runnable. */ - static async fromExamples(examples, args) { - const selector = new LengthBasedExampleSelector(args); - await Promise.all(examples.map((eg) => selector.addExample(eg))); - return selector; - } -}; - -//#endregion - -//# sourceMappingURL=length_based.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/semantic_similarity.js - - - -//#region src/example_selectors/semantic_similarity.ts -function sortedValues(values) { - return Object.keys(values).sort().map((key) => values[key]); -} -/** -* Class that selects examples based on semantic similarity. It extends -* the BaseExampleSelector class. -* @example -* ```typescript -* const exampleSelector = await SemanticSimilarityExampleSelector.fromExamples( -* [ -* { input: "happy", output: "sad" }, -* { input: "tall", output: "short" }, -* { input: "energetic", output: "lethargic" }, -* { input: "sunny", output: "gloomy" }, -* { input: "windy", output: "calm" }, -* ], -* new OpenAIEmbeddings(), -* HNSWLib, -* { k: 1 }, -* ); -* const dynamicPrompt = new FewShotPromptTemplate({ -* exampleSelector, -* examplePrompt: PromptTemplate.fromTemplate( -* "Input: {input}\nOutput: {output}", -* ), -* prefix: "Give the antonym of every input", -* suffix: "Input: {adjective}\nOutput:", -* inputVariables: ["adjective"], -* }); -* console.log(await dynamicPrompt.format({ adjective: "rainy" })); -* ``` -*/ -var SemanticSimilarityExampleSelector = class SemanticSimilarityExampleSelector extends BaseExampleSelector { - vectorStoreRetriever; - exampleKeys; - inputKeys; - constructor(data) { - super(data); - this.exampleKeys = data.exampleKeys; - this.inputKeys = data.inputKeys; - if (data.vectorStore !== void 0) this.vectorStoreRetriever = data.vectorStore.asRetriever({ - k: data.k ?? 4, - filter: data.filter - }); - else if (data.vectorStoreRetriever) this.vectorStoreRetriever = data.vectorStoreRetriever; - else throw new Error(`You must specify one of "vectorStore" and "vectorStoreRetriever".`); + pick(keys) { + return this.pipe(new RunnablePick(keys)); } /** - * Method that adds a new example to the vectorStore. The example is - * converted to a string and added to the vectorStore as a document. - * @param example The example to be added to the vectorStore. - * @returns Promise that resolves when the example has been added to the vectorStore. + * Assigns new fields to the dict output of this runnable. Returns a new runnable. */ - async addExample(example) { - const inputKeys = this.inputKeys ?? Object.keys(example); - const stringExample = sortedValues(inputKeys.reduce((acc, key) => ({ - ...acc, - [key]: example[key] - }), {})).join(" "); - await this.vectorStoreRetriever.addDocuments([new Document({ - pageContent: stringExample, - metadata: example - })]); + assign(mapping) { + return this.pipe(new RunnableAssign(new RunnableMap({ steps: mapping }))); } /** - * Method that selects which examples to use based on semantic similarity. - * It performs a similarity search in the vectorStore using the input - * variables and returns the examples with the highest similarity. - * @param inputVariables The input variables used for the similarity search. - * @returns Promise that resolves with an array of the selected examples. + * Default implementation of transform, which buffers input and then calls stream. + * Subclasses should override this method if they can start producing output while + * input is still being generated. + * @param generator + * @param options */ - async selectExamples(inputVariables) { - const inputKeys = this.inputKeys ?? Object.keys(inputVariables); - const query = sortedValues(inputKeys.reduce((acc, key) => ({ - ...acc, - [key]: inputVariables[key] - }), {})).join(" "); - const exampleDocs = await this.vectorStoreRetriever.invoke(query); - const examples = exampleDocs.map((doc) => doc.metadata); - if (this.exampleKeys) return examples.map((example) => this.exampleKeys.reduce((acc, key) => ({ - ...acc, - [key]: example[key] - }), {})); - return examples; + async *transform(generator, options) { + let finalChunk; + for await (const chunk of generator) if (finalChunk === void 0) finalChunk = chunk; + else finalChunk = this._concatOutputChunks(finalChunk, chunk); + yield* this._streamIterator(finalChunk, ensureConfig(options)); } /** - * Static method that creates a new instance of - * SemanticSimilarityExampleSelector. It takes a list of examples, an - * instance of Embeddings, a VectorStore class, and an options object as - * parameters. It converts the examples to strings, creates a VectorStore - * from the strings and the embeddings, and returns a new - * SemanticSimilarityExampleSelector with the created VectorStore and the - * options provided. - * @param examples The list of examples to be used. - * @param embeddings The instance of Embeddings to be used. - * @param vectorStoreCls The VectorStore class to be used. - * @param options The options object for the SemanticSimilarityExampleSelector. - * @returns Promise that resolves with a new instance of SemanticSimilarityExampleSelector. + * Stream all output from a runnable, as reported to the callback system. + * This includes all inner runs of LLMs, Retrievers, Tools, etc. + * Output is streamed as Log objects, which include a list of + * jsonpatch ops that describe how the state of the run has changed in each + * step, and the final state of the run. + * The jsonpatch ops can be applied in order to construct state. + * @param input + * @param options + * @param streamOptions */ - static async fromExamples(examples, embeddings, vectorStoreCls, options = {}) { - const inputKeys = options.inputKeys ?? null; - const stringExamples = examples.map((example) => sortedValues(inputKeys ? inputKeys.reduce((acc, key) => ({ - ...acc, - [key]: example[key] - }), {}) : example).join(" ")); - const vectorStore = await vectorStoreCls.fromTexts(stringExamples, examples, embeddings, options); - return new SemanticSimilarityExampleSelector({ - vectorStore, - k: options.k ?? 4, - exampleKeys: options.exampleKeys, - inputKeys: options.inputKeys + async *streamLog(input, options, streamOptions) { + const logStreamCallbackHandler = new LogStreamCallbackHandler({ + ...streamOptions, + autoClose: false, + _schemaFormat: "original" }); + const config = ensureConfig(options); + yield* this._streamLog(input, logStreamCallbackHandler, config); } -}; - -//#endregion - -//# sourceMappingURL=semantic_similarity.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/index.js - - - - - - -//#region src/example_selectors/index.ts -var example_selectors_exports = {}; -__export(example_selectors_exports, { - BaseExampleSelector: () => BaseExampleSelector, - BasePromptSelector: () => BasePromptSelector, - ConditionalPromptSelector: () => ConditionalPromptSelector, - LengthBasedExampleSelector: () => LengthBasedExampleSelector, - SemanticSimilarityExampleSelector: () => SemanticSimilarityExampleSelector, - isChatModel: () => isChatModel, - isLLM: () => isLLM -}); - -//#endregion - -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/indexing/record_manager.js - - -//#region src/indexing/record_manager.ts -const UUIDV5_NAMESPACE = "10f90ea3-90a4-4962-bf75-83a0f3c1c62a"; -var RecordManager = class extends Serializable { - lc_namespace = ["langchain", "recordmanagers"]; -}; - -//#endregion - -//# sourceMappingURL=record_manager.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/indexing/base.js - - - - - - -//#region src/indexing/base.ts -/** -* HashedDocument is a Document with hashes calculated. -* Hashes are calculated based on page content and metadata. -* It is used for indexing. -*/ -var _HashedDocument = class { - uid; - hash_; - contentHash; - metadataHash; - pageContent; - metadata; - keyEncoder = sha256; - constructor(fields) { - this.uid = fields.uid; - this.pageContent = fields.pageContent; - this.metadata = fields.metadata; - } - makeDefaultKeyEncoder(keyEncoderFn) { - this.keyEncoder = keyEncoderFn; - } - calculateHashes() { - const forbiddenKeys = [ - "hash_", - "content_hash", - "metadata_hash" - ]; - for (const key of forbiddenKeys) if (key in this.metadata) throw new Error(`Metadata cannot contain key ${key} as it is reserved for internal use. Restricted keys: [${forbiddenKeys.join(", ")}]`); - const contentHash = this._hashStringToUUID(this.pageContent); + async *_streamLog(input, logStreamCallbackHandler, config) { + const { callbacks } = config; + if (callbacks === void 0) config.callbacks = [logStreamCallbackHandler]; + else if (Array.isArray(callbacks)) config.callbacks = callbacks.concat([logStreamCallbackHandler]); + else { + const copiedCallbacks = callbacks.copy(); + copiedCallbacks.addHandler(logStreamCallbackHandler, true); + config.callbacks = copiedCallbacks; + } + const runnableStreamPromise = this.stream(input, config); + async function consumeRunnableStream() { + try { + const runnableStream = await runnableStreamPromise; + for await (const chunk of runnableStream) { + const patch = new RunLogPatch({ ops: [{ + op: "add", + path: "/streamed_output/-", + value: chunk + }] }); + await logStreamCallbackHandler.writer.write(patch); + } + } finally { + await logStreamCallbackHandler.writer.close(); + } + } + const runnableStreamConsumePromise = consumeRunnableStream(); try { - const metadataHash = this._hashNestedDictToUUID(this.metadata); - this.contentHash = contentHash; - this.metadataHash = metadataHash; - } catch (e) { - throw new Error(`Failed to hash metadata: ${e}. Please use a dict that can be serialized using json.`); + for await (const log of logStreamCallbackHandler) yield log; + } finally { + await runnableStreamConsumePromise; } - this.hash_ = this._hashStringToUUID(this.contentHash + this.metadataHash); - if (!this.uid) this.uid = this.hash_; } - toDocument() { - return new Document({ - pageContent: this.pageContent, - metadata: this.metadata - }); + streamEvents(input, options, streamOptions) { + let stream; + if (options.version === "v1") stream = this._streamEventsV1(input, options, streamOptions); + else if (options.version === "v2") stream = this._streamEventsV2(input, options, streamOptions); + else throw new Error(`Only versions "v1" and "v2" of the schema are currently supported.`); + if (options.encoding === "text/event-stream") return convertToHttpEventStream(stream); + else return IterableReadableStream.fromAsyncGenerator(stream); } - static fromDocument(document, uid) { - const doc = new this({ - pageContent: document.pageContent, - metadata: document.metadata, - uid: uid || document.uid + async *_streamEventsV2(input, options, streamOptions) { + const eventStreamer = new EventStreamCallbackHandler({ + ...streamOptions, + autoClose: false }); - doc.calculateHashes(); - return doc; - } - _hashStringToUUID(inputString) { - const hash_value = this.keyEncoder(inputString); - return v5(hash_value, UUIDV5_NAMESPACE); - } - _hashNestedDictToUUID(data) { - const serialized_data = JSON.stringify(data, Object.keys(data).sort()); - const hash_value = this.keyEncoder(serialized_data); - return v5(hash_value, UUIDV5_NAMESPACE); - } -}; -function _batch(size, iterable) { - const batches = []; - let currentBatch = []; - iterable.forEach((item) => { - currentBatch.push(item); - if (currentBatch.length >= size) { - batches.push(currentBatch); - currentBatch = []; - } - }); - if (currentBatch.length > 0) batches.push(currentBatch); - return batches; -} -function _deduplicateInOrder(hashedDocuments) { - const seen = /* @__PURE__ */ new Set(); - const deduplicated = []; - for (const hashedDoc of hashedDocuments) { - if (!hashedDoc.hash_) throw new Error("Hashed document does not have a hash"); - if (!seen.has(hashedDoc.hash_)) { - seen.add(hashedDoc.hash_); - deduplicated.push(hashedDoc); + const config = ensureConfig(options); + const runId = config.runId ?? v4(); + config.runId = runId; + const callbacks = config.callbacks; + if (callbacks === void 0) config.callbacks = [eventStreamer]; + else if (Array.isArray(callbacks)) config.callbacks = callbacks.concat(eventStreamer); + else { + const copiedCallbacks = callbacks.copy(); + copiedCallbacks.addHandler(eventStreamer, true); + config.callbacks = copiedCallbacks; } - } - return deduplicated; -} -function _getSourceIdAssigner(sourceIdKey) { - if (sourceIdKey === null) return (_doc) => null; - else if (typeof sourceIdKey === "string") return (doc) => doc.metadata[sourceIdKey]; - else if (typeof sourceIdKey === "function") return sourceIdKey; - else throw new Error(`sourceIdKey should be null, a string or a function, got ${typeof sourceIdKey}`); -} -const _isBaseDocumentLoader = (arg) => { - if ("load" in arg && typeof arg.load === "function" && "loadAndSplit" in arg && typeof arg.loadAndSplit === "function") return true; - return false; -}; -/** -* Index data from the doc source into the vector store. -* -* Indexing functionality uses a manager to keep track of which documents -* are in the vector store. -* -* This allows us to keep track of which documents were updated, and which -* documents were deleted, which documents should be skipped. -* -* For the time being, documents are indexed using their hashes, and users -* are not able to specify the uid of the document. -* -* @param {IndexArgs} args -* @param {BaseDocumentLoader | DocumentInterface[]} args.docsSource The source of documents to index. Can be a DocumentLoader or a list of Documents. -* @param {RecordManagerInterface} args.recordManager The record manager to use for keeping track of indexed documents. -* @param {VectorStore} args.vectorStore The vector store to use for storing the documents. -* @param {IndexOptions | undefined} args.options Options for indexing. -* @returns {Promise} -*/ -async function index(args) { - const { docsSource, recordManager, vectorStore, options } = args; - const { batchSize = 100, cleanup, sourceIdKey, cleanupBatchSize = 1e3, forceUpdate = false } = options ?? {}; - if (cleanup === "incremental" && !sourceIdKey) throw new Error("sourceIdKey is required when cleanup mode is incremental. Please provide through 'options.sourceIdKey'."); - const docs = _isBaseDocumentLoader(docsSource) ? await docsSource.load() : docsSource; - const sourceIdAssigner = _getSourceIdAssigner(sourceIdKey ?? null); - const indexStartDt = await recordManager.getTime(); - let numAdded = 0; - let numDeleted = 0; - let numUpdated = 0; - let numSkipped = 0; - const batches = _batch(batchSize ?? 100, docs); - for (const batch of batches) { - const hashedDocs = _deduplicateInOrder(batch.map((doc) => _HashedDocument.fromDocument(doc))); - const sourceIds = hashedDocs.map((doc) => sourceIdAssigner(doc)); - if (cleanup === "incremental") hashedDocs.forEach((_hashedDoc, index$1) => { - const source = sourceIds[index$1]; - if (source === null) throw new Error("sourceIdKey must be provided when cleanup is incremental"); - }); - const batchExists = await recordManager.exists(hashedDocs.map((doc) => doc.uid)); - const uids = []; - const docsToIndex = []; - const docsToUpdate = []; - const seenDocs = /* @__PURE__ */ new Set(); - hashedDocs.forEach((hashedDoc, i) => { - const docExists = batchExists[i]; - if (docExists) if (forceUpdate) seenDocs.add(hashedDoc.uid); - else { - docsToUpdate.push(hashedDoc.uid); - return; + const abortController = new AbortController(); + const outerThis = this; + async function consumeRunnableStream() { + let signal; + let listener = null; + try { + if (options?.signal) if ("any" in AbortSignal) signal = AbortSignal.any([abortController.signal, options.signal]); + else { + signal = options.signal; + listener = () => { + abortController.abort(); + }; + options.signal.addEventListener("abort", listener, { once: true }); + } + else signal = abortController.signal; + const runnableStream = await outerThis.stream(input, { + ...config, + signal + }); + const tappedStream = eventStreamer.tapOutputIterable(runId, runnableStream); + for await (const _ of tappedStream) if (abortController.signal.aborted) break; + } finally { + await eventStreamer.finish(); + if (signal && listener) signal.removeEventListener("abort", listener); } - uids.push(hashedDoc.uid); - docsToIndex.push(hashedDoc.toDocument()); - }); - if (docsToUpdate.length > 0) { - await recordManager.update(docsToUpdate, { timeAtLeast: indexStartDt }); - numSkipped += docsToUpdate.length; - } - if (docsToIndex.length > 0) { - await vectorStore.addDocuments(docsToIndex, { ids: uids }); - numAdded += docsToIndex.length - seenDocs.size; - numUpdated += seenDocs.size; } - await recordManager.update(hashedDocs.map((doc) => doc.uid), { - timeAtLeast: indexStartDt, - groupIds: sourceIds - }); - if (cleanup === "incremental") { - sourceIds.forEach((sourceId) => { - if (!sourceId) throw new Error("Source id cannot be null"); - }); - const uidsToDelete = await recordManager.listKeys({ - before: indexStartDt, - groupIds: sourceIds - }); - if (uidsToDelete.length > 0) { - await vectorStore.delete({ ids: uidsToDelete }); - await recordManager.deleteKeys(uidsToDelete); - numDeleted += uidsToDelete.length; + const runnableStreamConsumePromise = consumeRunnableStream(); + let firstEventSent = false; + let firstEventRunId; + try { + for await (const event of eventStreamer) { + if (!firstEventSent) { + event.data.input = input; + firstEventSent = true; + firstEventRunId = event.run_id; + yield event; + continue; + } + if (event.run_id === firstEventRunId && event.event.endsWith("_end")) { + if (event.data?.input) delete event.data.input; + } + yield event; } + } finally { + abortController.abort(); + await runnableStreamConsumePromise; } } - if (cleanup === "full") { - let uidsToDelete = await recordManager.listKeys({ - before: indexStartDt, - limit: cleanupBatchSize + async *_streamEventsV1(input, options, streamOptions) { + let runLog; + let hasEncounteredStartEvent = false; + const config = ensureConfig(options); + const rootTags = config.tags ?? []; + const rootMetadata = config.metadata ?? {}; + const rootName = config.runName ?? this.getName(); + const logStreamCallbackHandler = new LogStreamCallbackHandler({ + ...streamOptions, + autoClose: false, + _schemaFormat: "streaming_events" }); - while (uidsToDelete.length > 0) { - await vectorStore.delete({ ids: uidsToDelete }); - await recordManager.deleteKeys(uidsToDelete); - numDeleted += uidsToDelete.length; - uidsToDelete = await recordManager.listKeys({ - before: indexStartDt, - limit: cleanupBatchSize - }); + const rootEventFilter = new _RootEventFilter({ ...streamOptions }); + const logStream = this._streamLog(input, logStreamCallbackHandler, config); + for await (const log of logStream) { + if (!runLog) runLog = RunLog.fromRunLogPatch(log); + else runLog = runLog.concat(log); + if (runLog.state === void 0) throw new Error(`Internal error: "streamEvents" state is missing. Please open a bug report.`); + if (!hasEncounteredStartEvent) { + hasEncounteredStartEvent = true; + const state$2 = { ...runLog.state }; + const event = { + run_id: state$2.id, + event: `on_${state$2.type}_start`, + name: rootName, + tags: rootTags, + metadata: rootMetadata, + data: { input } + }; + if (rootEventFilter.includeEvent(event, state$2.type)) yield event; + } + const paths = log.ops.filter((op) => op.path.startsWith("/logs/")).map((op) => op.path.split("/")[2]); + const dedupedPaths = [...new Set(paths)]; + for (const path of dedupedPaths) { + let eventType; + let data = {}; + const logEntry = runLog.state.logs[path]; + if (logEntry.end_time === void 0) if (logEntry.streamed_output.length > 0) eventType = "stream"; + else eventType = "start"; + else eventType = "end"; + if (eventType === "start") { + if (logEntry.inputs !== void 0) data.input = logEntry.inputs; + } else if (eventType === "end") { + if (logEntry.inputs !== void 0) data.input = logEntry.inputs; + data.output = logEntry.final_output; + } else if (eventType === "stream") { + const chunkCount = logEntry.streamed_output.length; + if (chunkCount !== 1) throw new Error(`Expected exactly one chunk of streamed output, got ${chunkCount} instead. Encountered in: "${logEntry.name}"`); + data = { chunk: logEntry.streamed_output[0] }; + logEntry.streamed_output = []; + } + yield { + event: `on_${logEntry.type}_${eventType}`, + name: logEntry.name, + run_id: logEntry.id, + tags: logEntry.tags, + metadata: logEntry.metadata, + data + }; + } + const { state: state$1 } = runLog; + if (state$1.streamed_output.length > 0) { + const chunkCount = state$1.streamed_output.length; + if (chunkCount !== 1) throw new Error(`Expected exactly one chunk of streamed output, got ${chunkCount} instead. Encountered in: "${state$1.name}"`); + const data = { chunk: state$1.streamed_output[0] }; + state$1.streamed_output = []; + const event = { + event: `on_${state$1.type}_stream`, + run_id: state$1.id, + tags: rootTags, + metadata: rootMetadata, + name: rootName, + data + }; + if (rootEventFilter.includeEvent(event, state$1.type)) yield event; + } + } + const state = runLog?.state; + if (state !== void 0) { + const event = { + event: `on_${state.type}_end`, + name: rootName, + run_id: state.id, + tags: rootTags, + metadata: rootMetadata, + data: { output: state.final_output } + }; + if (rootEventFilter.includeEvent(event, state.type)) yield event; } } - return { - numAdded, - numDeleted, - numUpdated, - numSkipped - }; -} - -//#endregion - -//# sourceMappingURL=base.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/indexing/index.js - - - - -//#region src/indexing/index.ts -var indexing_exports = {}; -__export(indexing_exports, { - RecordManager: () => RecordManager, - UUIDV5_NAMESPACE: () => UUIDV5_NAMESPACE, - _HashedDocument: () => _HashedDocument, - _batch: () => _batch, - _deduplicateInOrder: () => _deduplicateInOrder, - _getSourceIdAssigner: () => _getSourceIdAssigner, - _isBaseDocumentLoader: () => _isBaseDocumentLoader, - index: () => index -}); - -//#endregion - -//# sourceMappingURL=index.js.map -// EXTERNAL MODULE: ./node_modules/base64-js/index.js -var base64_js = __nccwpck_require__(8793); -;// CONCATENATED MODULE: ./node_modules/js-tiktoken/dist/chunk-VL2OQCWN.js - - -var chunk_VL2OQCWN_defProp = Object.defineProperty; -var __defNormalProp = (obj, key, value) => key in obj ? chunk_VL2OQCWN_defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; -var __publicField = (obj, key, value) => { - __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); - return value; -}; - -// src/utils.ts -function never(_) { -} -function bytePairMerge(piece, ranks) { - let parts = Array.from( - { length: piece.length }, - (_, i) => ({ start: i, end: i + 1 }) - ); - while (parts.length > 1) { - let minRank = null; - for (let i = 0; i < parts.length - 1; i++) { - const slice = piece.slice(parts[i].start, parts[i + 1].end); - const rank = ranks.get(slice.join(",")); - if (rank == null) - continue; - if (minRank == null || rank < minRank[0]) { - minRank = [rank, i]; - } - } - if (minRank != null) { - const i = minRank[1]; - parts[i] = { start: parts[i].start, end: parts[i + 1].end }; - parts.splice(i + 1, 1); - } else { - break; - } - } - return parts; -} -function bytePairEncode(piece, ranks) { - if (piece.length === 1) - return [ranks.get(piece.join(","))]; - return bytePairMerge(piece, ranks).map((p) => ranks.get(piece.slice(p.start, p.end).join(","))).filter((x) => x != null); -} -function chunk_VL2OQCWN_escapeRegex(str) { - return str.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&"); -} -var _Tiktoken = class { - /** @internal */ - specialTokens; - /** @internal */ - inverseSpecialTokens; - /** @internal */ - patStr; - /** @internal */ - textEncoder = new TextEncoder(); - /** @internal */ - textDecoder = new TextDecoder("utf-8"); - /** @internal */ - rankMap = /* @__PURE__ */ new Map(); - /** @internal */ - textMap = /* @__PURE__ */ new Map(); - constructor(ranks, extendedSpecialTokens) { - this.patStr = ranks.pat_str; - const uncompressed = ranks.bpe_ranks.split("\n").filter(Boolean).reduce((memo, x) => { - const [_, offsetStr, ...tokens] = x.split(" "); - const offset = Number.parseInt(offsetStr, 10); - tokens.forEach((token, i) => memo[token] = offset + i); - return memo; - }, {}); - for (const [token, rank] of Object.entries(uncompressed)) { - const bytes = base64_js.toByteArray(token); - this.rankMap.set(bytes.join(","), rank); - this.textMap.set(rank, bytes); - } - this.specialTokens = { ...ranks.special_tokens, ...extendedSpecialTokens }; - this.inverseSpecialTokens = Object.entries(this.specialTokens).reduce((memo, [text, rank]) => { - memo[rank] = this.textEncoder.encode(text); - return memo; - }, {}); - } - encode(text, allowedSpecial = [], disallowedSpecial = "all") { - const regexes = new RegExp(this.patStr, "ug"); - const specialRegex = _Tiktoken.specialTokenRegex( - Object.keys(this.specialTokens) - ); - const ret = []; - const allowedSpecialSet = new Set( - allowedSpecial === "all" ? Object.keys(this.specialTokens) : allowedSpecial - ); - const disallowedSpecialSet = new Set( - disallowedSpecial === "all" ? Object.keys(this.specialTokens).filter( - (x) => !allowedSpecialSet.has(x) - ) : disallowedSpecial - ); - if (disallowedSpecialSet.size > 0) { - const disallowedSpecialRegex = _Tiktoken.specialTokenRegex([ - ...disallowedSpecialSet - ]); - const specialMatch = text.match(disallowedSpecialRegex); - if (specialMatch != null) { - throw new Error( - `The text contains a special token that is not allowed: ${specialMatch[0]}` - ); - } - } - let start = 0; - while (true) { - let nextSpecial = null; - let startFind = start; - while (true) { - specialRegex.lastIndex = startFind; - nextSpecial = specialRegex.exec(text); - if (nextSpecial == null || allowedSpecialSet.has(nextSpecial[0])) - break; - startFind = nextSpecial.index + 1; - } - const end = nextSpecial?.index ?? text.length; - for (const match of text.substring(start, end).matchAll(regexes)) { - const piece = this.textEncoder.encode(match[0]); - const token2 = this.rankMap.get(piece.join(",")); - if (token2 != null) { - ret.push(token2); - continue; - } - ret.push(...bytePairEncode(piece, this.rankMap)); - } - if (nextSpecial == null) - break; - let token = this.specialTokens[nextSpecial[0]]; - ret.push(token); - start = nextSpecial.index + nextSpecial[0].length; - } - return ret; - } - decode(tokens) { - const res = []; - let length = 0; - for (let i2 = 0; i2 < tokens.length; ++i2) { - const token = tokens[i2]; - const bytes = this.textMap.get(token) ?? this.inverseSpecialTokens[token]; - if (bytes != null) { - res.push(bytes); - length += bytes.length; - } - } - const mergedArray = new Uint8Array(length); - let i = 0; - for (const bytes of res) { - mergedArray.set(bytes, i); - i += bytes.length; - } - return this.textDecoder.decode(mergedArray); - } -}; -var Tiktoken = _Tiktoken; -__publicField(Tiktoken, "specialTokenRegex", (tokens) => { - return new RegExp(tokens.map((i) => chunk_VL2OQCWN_escapeRegex(i)).join("|"), "g"); -}); -function getEncodingNameForModel(model) { - switch (model) { - case "gpt2": { - return "gpt2"; - } - case "code-cushman-001": - case "code-cushman-002": - case "code-davinci-001": - case "code-davinci-002": - case "cushman-codex": - case "davinci-codex": - case "davinci-002": - case "text-davinci-002": - case "text-davinci-003": { - return "p50k_base"; - } - case "code-davinci-edit-001": - case "text-davinci-edit-001": { - return "p50k_edit"; - } - case "ada": - case "babbage": - case "babbage-002": - case "code-search-ada-code-001": - case "code-search-babbage-code-001": - case "curie": - case "davinci": - case "text-ada-001": - case "text-babbage-001": - case "text-curie-001": - case "text-davinci-001": - case "text-search-ada-doc-001": - case "text-search-babbage-doc-001": - case "text-search-curie-doc-001": - case "text-search-davinci-doc-001": - case "text-similarity-ada-001": - case "text-similarity-babbage-001": - case "text-similarity-curie-001": - case "text-similarity-davinci-001": { - return "r50k_base"; - } - case "gpt-3.5-turbo-instruct-0914": - case "gpt-3.5-turbo-instruct": - case "gpt-3.5-turbo-16k-0613": - case "gpt-3.5-turbo-16k": - case "gpt-3.5-turbo-0613": - case "gpt-3.5-turbo-0301": - case "gpt-3.5-turbo": - case "gpt-4-32k-0613": - case "gpt-4-32k-0314": - case "gpt-4-32k": - case "gpt-4-0613": - case "gpt-4-0314": - case "gpt-4": - case "gpt-3.5-turbo-1106": - case "gpt-35-turbo": - case "gpt-4-1106-preview": - case "gpt-4-vision-preview": - case "gpt-3.5-turbo-0125": - case "gpt-4-turbo": - case "gpt-4-turbo-2024-04-09": - case "gpt-4-turbo-preview": - case "gpt-4-0125-preview": - case "text-embedding-ada-002": - case "text-embedding-3-small": - case "text-embedding-3-large": { - return "cl100k_base"; - } - case "gpt-4o": - case "gpt-4o-2024-05-13": - case "gpt-4o-2024-08-06": - case "gpt-4o-2024-11-20": - case "gpt-4o-mini-2024-07-18": - case "gpt-4o-mini": - case "gpt-4o-search-preview": - case "gpt-4o-search-preview-2025-03-11": - case "gpt-4o-mini-search-preview": - case "gpt-4o-mini-search-preview-2025-03-11": - case "gpt-4o-audio-preview": - case "gpt-4o-audio-preview-2024-12-17": - case "gpt-4o-audio-preview-2024-10-01": - case "gpt-4o-mini-audio-preview": - case "gpt-4o-mini-audio-preview-2024-12-17": - case "o1": - case "o1-2024-12-17": - case "o1-mini": - case "o1-mini-2024-09-12": - case "o1-preview": - case "o1-preview-2024-09-12": - case "o1-pro": - case "o1-pro-2025-03-19": - case "o3": - case "o3-2025-04-16": - case "o3-mini": - case "o3-mini-2025-01-31": - case "o4-mini": - case "o4-mini-2025-04-16": - case "chatgpt-4o-latest": - case "gpt-4o-realtime": - case "gpt-4o-realtime-preview-2024-10-01": - case "gpt-4o-realtime-preview-2024-12-17": - case "gpt-4o-mini-realtime-preview": - case "gpt-4o-mini-realtime-preview-2024-12-17": - case "gpt-4.1": - case "gpt-4.1-2025-04-14": - case "gpt-4.1-mini": - case "gpt-4.1-mini-2025-04-14": - case "gpt-4.1-nano": - case "gpt-4.1-nano-2025-04-14": - case "gpt-4.5-preview": - case "gpt-4.5-preview-2025-02-27": - case "gpt-5": - case "gpt-5-2025-08-07": - case "gpt-5-nano": - case "gpt-5-nano-2025-08-07": - case "gpt-5-mini": - case "gpt-5-mini-2025-08-07": - case "gpt-5-chat-latest": { - return "o200k_base"; - } - default: - throw new Error("Unknown model"); - } -} - - - -;// CONCATENATED MODULE: ./node_modules/js-tiktoken/dist/lite.js - - -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/tiktoken.js - - - - -//#region src/utils/tiktoken.ts -var tiktoken_exports = {}; -__export(tiktoken_exports, { - encodingForModel: () => encodingForModel, - getEncoding: () => getEncoding -}); -const cache = {}; -const caller = /* @__PURE__ */ new async_caller_AsyncCaller({}); -async function getEncoding(encoding) { - if (!(encoding in cache)) cache[encoding] = caller.fetch(`https://tiktoken.pages.dev/js/${encoding}.json`).then((res) => res.json()).then((data) => new Tiktoken(data)).catch((e) => { - delete cache[encoding]; - throw e; - }); - return await cache[encoding]; -} -async function encodingForModel(model) { - return getEncoding(getEncodingNameForModel(model)); -} - -//#endregion - -//# sourceMappingURL=tiktoken.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/base.js - - - - - - - - -//#region src/language_models/base.ts -var language_models_base_base_exports = {}; -__export(language_models_base_base_exports, { - BaseLangChain: () => BaseLangChain, - BaseLanguageModel: () => BaseLanguageModel, - calculateMaxTokens: () => calculateMaxTokens, - getEmbeddingContextSize: () => getEmbeddingContextSize, - getModelContextSize: () => getModelContextSize, - getModelNameForTiktoken: () => getModelNameForTiktoken, - isOpenAITool: () => isOpenAITool -}); -const getModelNameForTiktoken = (modelName) => { - if (modelName.startsWith("gpt-5")) return "gpt-5"; - if (modelName.startsWith("gpt-3.5-turbo-16k")) return "gpt-3.5-turbo-16k"; - if (modelName.startsWith("gpt-3.5-turbo-")) return "gpt-3.5-turbo"; - if (modelName.startsWith("gpt-4-32k")) return "gpt-4-32k"; - if (modelName.startsWith("gpt-4-")) return "gpt-4"; - if (modelName.startsWith("gpt-4o")) return "gpt-4o"; - return modelName; + static isRunnable(thing) { + return isRunnableInterface(thing); + } + /** + * Bind lifecycle listeners to a Runnable, returning a new Runnable. + * The Run object contains information about the run, including its id, + * type, input, output, error, startTime, endTime, and any tags or metadata + * added to the run. + * + * @param {Object} params - The object containing the callback functions. + * @param {(run: Run) => void} params.onStart - Called before the runnable starts running, with the Run object. + * @param {(run: Run) => void} params.onEnd - Called after the runnable finishes running, with the Run object. + * @param {(run: Run) => void} params.onError - Called if the runnable throws an error, with the Run object. + */ + withListeners({ onStart, onEnd, onError }) { + return new RunnableBinding({ + bound: this, + config: {}, + configFactories: [(config) => ({ callbacks: [new RootListenersTracer({ + config, + onStart, + onEnd, + onError + })] })] + }); + } + /** + * Convert a runnable to a tool. Return a new instance of `RunnableToolLike` + * which contains the runnable, name, description and schema. + * + * @template {T extends RunInput = RunInput} RunInput - The input type of the runnable. Should be the same as the `RunInput` type of the runnable. + * + * @param fields + * @param {string | undefined} [fields.name] The name of the tool. If not provided, it will default to the name of the runnable. + * @param {string | undefined} [fields.description] The description of the tool. Falls back to the description on the Zod schema if not provided, or undefined if neither are provided. + * @param {z.ZodType} [fields.schema] The Zod schema for the input of the tool. Infers the Zod type from the input type of the runnable. + * @returns {RunnableToolLike, RunOutput>} An instance of `RunnableToolLike` which is a runnable that can be used as a tool. + */ + asTool(fields) { + return convertRunnableToTool(this, fields); + } }; -const getEmbeddingContextSize = (modelName) => { - switch (modelName) { - case "text-embedding-ada-002": return 8191; - default: return 2046; +/** +* Wraps a runnable and applies partial config upon invocation. +* +* @example +* ```typescript +* import { +* type RunnableConfig, +* RunnableLambda, +* } from "@langchain/core/runnables"; +* +* const enhanceProfile = ( +* profile: Record, +* config?: RunnableConfig +* ) => { +* if (config?.configurable?.role) { +* return { ...profile, role: config.configurable.role }; +* } +* return profile; +* }; +* +* const runnable = RunnableLambda.from(enhanceProfile); +* +* // Bind configuration to the runnable to set the user's role dynamically +* const adminRunnable = runnable.withConfig({ configurable: { role: "Admin" } }); +* const userRunnable = runnable.withConfig({ configurable: { role: "User" } }); +* +* const result1 = await adminRunnable.invoke({ +* name: "Alice", +* email: "alice@example.com" +* }); +* +* // { name: "Alice", email: "alice@example.com", role: "Admin" } +* +* const result2 = await userRunnable.invoke({ +* name: "Bob", +* email: "bob@example.com" +* }); +* +* // { name: "Bob", email: "bob@example.com", role: "User" } +* ``` +*/ +var RunnableBinding = class RunnableBinding extends Runnable { + static lc_name() { + return "RunnableBinding"; + } + lc_namespace = ["langchain_core", "runnables"]; + lc_serializable = true; + bound; + config; + kwargs; + configFactories; + constructor(fields) { + super(fields); + this.bound = fields.bound; + this.kwargs = fields.kwargs; + this.config = fields.config; + this.configFactories = fields.configFactories; + } + getName(suffix) { + return this.bound.getName(suffix); + } + async _mergeConfig(...options) { + const config = mergeConfigs(this.config, ...options); + return mergeConfigs(config, ...this.configFactories ? await Promise.all(this.configFactories.map(async (configFactory) => await configFactory(config))) : []); + } + withConfig(config) { + return new this.constructor({ + bound: this.bound, + kwargs: this.kwargs, + config: { + ...this.config, + ...config + } + }); + } + withRetry(fields) { + return new RunnableRetry({ + bound: this.bound, + kwargs: this.kwargs, + config: this.config, + maxAttemptNumber: fields?.stopAfterAttempt, + ...fields + }); + } + async invoke(input, options) { + return this.bound.invoke(input, await this._mergeConfig(options, this.kwargs)); + } + async batch(inputs, options, batchOptions) { + const mergedOptions = Array.isArray(options) ? await Promise.all(options.map(async (individualOption) => this._mergeConfig(ensureConfig(individualOption), this.kwargs))) : await this._mergeConfig(ensureConfig(options), this.kwargs); + return this.bound.batch(inputs, mergedOptions, batchOptions); + } + /** @internal */ + _concatOutputChunks(first, second) { + return this.bound._concatOutputChunks(first, second); + } + async *_streamIterator(input, options) { + yield* this.bound._streamIterator(input, await this._mergeConfig(ensureConfig(options), this.kwargs)); + } + async stream(input, options) { + return this.bound.stream(input, await this._mergeConfig(ensureConfig(options), this.kwargs)); + } + async *transform(generator, options) { + yield* this.bound.transform(generator, await this._mergeConfig(ensureConfig(options), this.kwargs)); + } + streamEvents(input, options, streamOptions) { + const outerThis = this; + const generator = async function* () { + yield* outerThis.bound.streamEvents(input, { + ...await outerThis._mergeConfig(ensureConfig(options), outerThis.kwargs), + version: options.version + }, streamOptions); + }; + return IterableReadableStream.fromAsyncGenerator(generator()); + } + static isRunnableBinding(thing) { + return thing.bound && Runnable.isRunnable(thing.bound); + } + /** + * Bind lifecycle listeners to a Runnable, returning a new Runnable. + * The Run object contains information about the run, including its id, + * type, input, output, error, startTime, endTime, and any tags or metadata + * added to the run. + * + * @param {Object} params - The object containing the callback functions. + * @param {(run: Run) => void} params.onStart - Called before the runnable starts running, with the Run object. + * @param {(run: Run) => void} params.onEnd - Called after the runnable finishes running, with the Run object. + * @param {(run: Run) => void} params.onError - Called if the runnable throws an error, with the Run object. + */ + withListeners({ onStart, onEnd, onError }) { + return new RunnableBinding({ + bound: this.bound, + kwargs: this.kwargs, + config: this.config, + configFactories: [(config) => ({ callbacks: [new RootListenersTracer({ + config, + onStart, + onEnd, + onError + })] })] + }); } }; /** -* Get the context window size (max input tokens) for a given model. +* A runnable that delegates calls to another runnable +* with each element of the input sequence. +* @example +* ```typescript +* import { RunnableEach, RunnableLambda } from "@langchain/core/runnables"; * -* Context window sizes are sourced from official model documentation: -* - OpenAI: https://platform.openai.com/docs/models -* - Anthropic: https://docs.anthropic.com/claude/docs/models-overview -* - Google: https://ai.google.dev/gemini/docs/models/gemini +* const toUpperCase = (input: string): string => input.toUpperCase(); +* const addGreeting = (input: string): string => `Hello, ${input}!`; * -* @param modelName - The name of the model -* @returns The context window size in tokens +* const upperCaseLambda = RunnableLambda.from(toUpperCase); +* const greetingLambda = RunnableLambda.from(addGreeting); +* +* const chain = new RunnableEach({ +* bound: upperCaseLambda.pipe(greetingLambda), +* }); +* +* const result = await chain.invoke(["alice", "bob", "carol"]) +* +* // ["Hello, ALICE!", "Hello, BOB!", "Hello, CAROL!"] +* ``` */ -const getModelContextSize = (modelName) => { - const normalizedName = getModelNameForTiktoken(modelName); - switch (normalizedName) { - case "gpt-5": - case "gpt-5-turbo": - case "gpt-5-turbo-preview": return 4e5; - case "gpt-4o": - case "gpt-4o-mini": - case "gpt-4o-2024-05-13": - case "gpt-4o-2024-08-06": return 128e3; - case "gpt-4-turbo": - case "gpt-4-turbo-preview": - case "gpt-4-turbo-2024-04-09": - case "gpt-4-0125-preview": - case "gpt-4-1106-preview": return 128e3; - case "gpt-4-32k": - case "gpt-4-32k-0314": - case "gpt-4-32k-0613": return 32768; - case "gpt-4": - case "gpt-4-0314": - case "gpt-4-0613": return 8192; - case "gpt-3.5-turbo-16k": - case "gpt-3.5-turbo-16k-0613": return 16384; - case "gpt-3.5-turbo": - case "gpt-3.5-turbo-0301": - case "gpt-3.5-turbo-0613": - case "gpt-3.5-turbo-1106": - case "gpt-3.5-turbo-0125": return 4096; - case "text-davinci-003": - case "text-davinci-002": return 4097; - case "text-davinci-001": return 2049; - case "text-curie-001": - case "text-babbage-001": - case "text-ada-001": return 2048; - case "code-davinci-002": - case "code-davinci-001": return 8e3; - case "code-cushman-001": return 2048; - case "claude-3-5-sonnet-20241022": - case "claude-3-5-sonnet-20240620": - case "claude-3-opus-20240229": - case "claude-3-sonnet-20240229": - case "claude-3-haiku-20240307": - case "claude-2.1": return 2e5; - case "claude-2.0": - case "claude-instant-1.2": return 1e5; - case "gemini-1.5-pro": - case "gemini-1.5-pro-latest": - case "gemini-1.5-flash": - case "gemini-1.5-flash-latest": return 1e6; - case "gemini-pro": - case "gemini-pro-vision": return 32768; - default: return 4097; +var RunnableEach = class RunnableEach extends Runnable { + static lc_name() { + return "RunnableEach"; + } + lc_serializable = true; + lc_namespace = ["langchain_core", "runnables"]; + bound; + constructor(fields) { + super(fields); + this.bound = fields.bound; + } + /** + * Invokes the runnable with the specified input and configuration. + * @param input The input to invoke the runnable with. + * @param config The configuration to invoke the runnable with. + * @returns A promise that resolves to the output of the runnable. + */ + async invoke(inputs, config) { + return this._callWithConfig(this._invoke.bind(this), inputs, config); + } + /** + * A helper method that is used to invoke the runnable with the specified input and configuration. + * @param input The input to invoke the runnable with. + * @param config The configuration to invoke the runnable with. + * @returns A promise that resolves to the output of the runnable. + */ + async _invoke(inputs, config, runManager) { + return this.bound.batch(inputs, config_patchConfig(config, { callbacks: runManager?.getChild() })); + } + /** + * Bind lifecycle listeners to a Runnable, returning a new Runnable. + * The Run object contains information about the run, including its id, + * type, input, output, error, startTime, endTime, and any tags or metadata + * added to the run. + * + * @param {Object} params - The object containing the callback functions. + * @param {(run: Run) => void} params.onStart - Called before the runnable starts running, with the Run object. + * @param {(run: Run) => void} params.onEnd - Called after the runnable finishes running, with the Run object. + * @param {(run: Run) => void} params.onError - Called if the runnable throws an error, with the Run object. + */ + withListeners({ onStart, onEnd, onError }) { + return new RunnableEach({ bound: this.bound.withListeners({ + onStart, + onEnd, + onError + }) }); + } +}; +/** +* Base class for runnables that can be retried a +* specified number of times. +* @example +* ```typescript +* import { +* RunnableLambda, +* RunnableRetry, +* } from "@langchain/core/runnables"; +* +* // Simulate an API call that fails +* const simulateApiCall = (input: string): string => { +* console.log(`Attempting API call with input: ${input}`); +* throw new Error("API call failed due to network issue"); +* }; +* +* const apiCallLambda = RunnableLambda.from(simulateApiCall); +* +* // Apply retry logic using the .withRetry() method +* const apiCallWithRetry = apiCallLambda.withRetry({ stopAfterAttempt: 3 }); +* +* // Alternatively, create a RunnableRetry instance manually +* const manualRetry = new RunnableRetry({ +* bound: apiCallLambda, +* maxAttemptNumber: 3, +* config: {}, +* }); +* +* // Example invocation using the .withRetry() method +* const res = await apiCallWithRetry +* .invoke("Request 1") +* .catch((error) => { +* console.error("Failed after multiple retries:", error.message); +* }); +* +* // Example invocation using the manual retry instance +* const res2 = await manualRetry +* .invoke("Request 2") +* .catch((error) => { +* console.error("Failed after multiple retries:", error.message); +* }); +* ``` +*/ +var RunnableRetry = class extends RunnableBinding { + static lc_name() { + return "RunnableRetry"; + } + lc_namespace = ["langchain_core", "runnables"]; + maxAttemptNumber = 3; + onFailedAttempt = () => {}; + constructor(fields) { + super(fields); + this.maxAttemptNumber = fields.maxAttemptNumber ?? this.maxAttemptNumber; + this.onFailedAttempt = fields.onFailedAttempt ?? this.onFailedAttempt; + } + _patchConfigForRetry(attempt, config, runManager) { + const tag = attempt > 1 ? `retry:attempt:${attempt}` : void 0; + return config_patchConfig(config, { callbacks: runManager?.getChild(tag) }); + } + async _invoke(input, config, runManager) { + return p_retry_pRetry((attemptNumber) => super.invoke(input, this._patchConfigForRetry(attemptNumber, config, runManager)), { + onFailedAttempt: ({ error }) => this.onFailedAttempt(error, input), + retries: Math.max(this.maxAttemptNumber - 1, 0), + randomize: true + }); + } + /** + * Method that invokes the runnable with the specified input, run manager, + * and config. It handles the retry logic by catching any errors and + * recursively invoking itself with the updated config for the next retry + * attempt. + * @param input The input for the runnable. + * @param runManager The run manager for the runnable. + * @param config The config for the runnable. + * @returns A promise that resolves to the output of the runnable. + */ + async invoke(input, config) { + return this._callWithConfig(this._invoke.bind(this), input, config); + } + async _batch(inputs, configs, runManagers, batchOptions) { + const resultsMap = {}; + try { + await p_retry_pRetry(async (attemptNumber) => { + const remainingIndexes = inputs.map((_, i) => i).filter((i) => resultsMap[i.toString()] === void 0 || resultsMap[i.toString()] instanceof Error); + const remainingInputs = remainingIndexes.map((i) => inputs[i]); + const patchedConfigs = remainingIndexes.map((i) => this._patchConfigForRetry(attemptNumber, configs?.[i], runManagers?.[i])); + const results = await super.batch(remainingInputs, patchedConfigs, { + ...batchOptions, + returnExceptions: true + }); + let firstException; + for (let i = 0; i < results.length; i += 1) { + const result = results[i]; + const resultMapIndex = remainingIndexes[i]; + if (result instanceof Error) { + if (firstException === void 0) { + firstException = result; + firstException.input = remainingInputs[i]; + } + } + resultsMap[resultMapIndex.toString()] = result; + } + if (firstException) throw firstException; + return results; + }, { + onFailedAttempt: ({ error }) => this.onFailedAttempt(error, error.input), + retries: Math.max(this.maxAttemptNumber - 1, 0), + randomize: true + }); + } catch (e) { + if (batchOptions?.returnExceptions !== true) throw e; + } + return Object.keys(resultsMap).sort((a, b) => parseInt(a, 10) - parseInt(b, 10)).map((key) => resultsMap[parseInt(key, 10)]); + } + async batch(inputs, options, batchOptions) { + return this._batchWithConfig(this._batch.bind(this), inputs, options, batchOptions); + } +}; +/** +* A sequence of runnables, where the output of each is the input of the next. +* @example +* ```typescript +* const promptTemplate = PromptTemplate.fromTemplate( +* "Tell me a joke about {topic}", +* ); +* const chain = RunnableSequence.from([promptTemplate, new ChatOpenAI({ model: "gpt-4o-mini" })]); +* const result = await chain.invoke({ topic: "bears" }); +* ``` +*/ +var RunnableSequence = class RunnableSequence extends Runnable { + static lc_name() { + return "RunnableSequence"; + } + first; + middle = []; + last; + omitSequenceTags = false; + lc_serializable = true; + lc_namespace = ["langchain_core", "runnables"]; + constructor(fields) { + super(fields); + this.first = fields.first; + this.middle = fields.middle ?? this.middle; + this.last = fields.last; + this.name = fields.name; + this.omitSequenceTags = fields.omitSequenceTags ?? this.omitSequenceTags; + } + get steps() { + return [ + this.first, + ...this.middle, + this.last + ]; + } + async invoke(input, options) { + const config = ensureConfig(options); + const callbackManager_ = await getCallbackManagerForConfig(config); + const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), config.runId, void 0, void 0, void 0, config?.runName); + delete config.runId; + let nextStepInput = input; + let finalOutput; + try { + const initialSteps = [this.first, ...this.middle]; + for (let i = 0; i < initialSteps.length; i += 1) { + const step = initialSteps[i]; + const promise = step.invoke(nextStepInput, config_patchConfig(config, { callbacks: runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:${i + 1}`) })); + nextStepInput = await raceWithSignal(promise, options?.signal); + } + if (options?.signal?.aborted) throw getAbortSignalError(options.signal); + finalOutput = await this.last.invoke(nextStepInput, config_patchConfig(config, { callbacks: runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:${this.steps.length}`) })); + } catch (e) { + await runManager?.handleChainError(e); + throw e; + } + await runManager?.handleChainEnd(base_coerceToDict(finalOutput, "output")); + return finalOutput; + } + async batch(inputs, options, batchOptions) { + const configList = this._getOptionsList(options ?? {}, inputs.length); + const callbackManagers = await Promise.all(configList.map(getCallbackManagerForConfig)); + const runManagers = await Promise.all(callbackManagers.map(async (callbackManager, i) => { + const handleStartRes = await callbackManager?.handleChainStart(this.toJSON(), base_coerceToDict(inputs[i], "input"), configList[i].runId, void 0, void 0, void 0, configList[i].runName); + delete configList[i].runId; + return handleStartRes; + })); + let nextStepInputs = inputs; + try { + for (let i = 0; i < this.steps.length; i += 1) { + const step = this.steps[i]; + const promise = step.batch(nextStepInputs, runManagers.map((runManager, j) => { + const childRunManager = runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:${i + 1}`); + return config_patchConfig(configList[j], { callbacks: childRunManager }); + }), batchOptions); + nextStepInputs = await raceWithSignal(promise, configList[0]?.signal); + } + } catch (e) { + await Promise.all(runManagers.map((runManager) => runManager?.handleChainError(e))); + throw e; + } + await Promise.all(runManagers.map((runManager) => runManager?.handleChainEnd(base_coerceToDict(nextStepInputs, "output")))); + return nextStepInputs; + } + /** @internal */ + _concatOutputChunks(first, second) { + return this.last._concatOutputChunks(first, second); + } + async *_streamIterator(input, options) { + const callbackManager_ = await getCallbackManagerForConfig(options); + const { runId,...otherOptions } = options ?? {}; + const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), runId, void 0, void 0, void 0, otherOptions?.runName); + const steps = [ + this.first, + ...this.middle, + this.last + ]; + let concatSupported = true; + let finalOutput; + async function* inputGenerator() { + yield input; + } + try { + let finalGenerator = steps[0].transform(inputGenerator(), config_patchConfig(otherOptions, { callbacks: runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:1`) })); + for (let i = 1; i < steps.length; i += 1) { + const step = steps[i]; + finalGenerator = await step.transform(finalGenerator, config_patchConfig(otherOptions, { callbacks: runManager?.getChild(this.omitSequenceTags ? void 0 : `seq:step:${i + 1}`) })); + } + for await (const chunk of finalGenerator) { + options?.signal?.throwIfAborted(); + yield chunk; + if (concatSupported) if (finalOutput === void 0) finalOutput = chunk; + else try { + finalOutput = this._concatOutputChunks(finalOutput, chunk); + } catch { + finalOutput = void 0; + concatSupported = false; + } + } + } catch (e) { + await runManager?.handleChainError(e); + throw e; + } + await runManager?.handleChainEnd(base_coerceToDict(finalOutput, "output")); } -}; -/** -* Whether or not the input matches the OpenAI tool definition. -* @param {unknown} tool The input to check. -* @returns {boolean} Whether the input is an OpenAI tool definition. -*/ -function isOpenAITool(tool) { - if (typeof tool !== "object" || !tool) return false; - if ("type" in tool && tool.type === "function" && "function" in tool && typeof tool.function === "object" && tool.function && "name" in tool.function && "parameters" in tool.function) return true; - return false; -} -const calculateMaxTokens = async ({ prompt, modelName }) => { - let numTokens; - try { - numTokens = (await encodingForModel(getModelNameForTiktoken(modelName))).encode(prompt).length; - } catch { - console.warn("Failed to calculate number of tokens, falling back to approximate count"); - numTokens = Math.ceil(prompt.length / 4); + getGraph(config) { + const graph = new Graph(); + let currentLastNode = null; + this.steps.forEach((step, index) => { + const stepGraph = step.getGraph(config); + if (index !== 0) stepGraph.trimFirstNode(); + if (index !== this.steps.length - 1) stepGraph.trimLastNode(); + graph.extend(stepGraph); + const stepFirstNode = stepGraph.firstNode(); + if (!stepFirstNode) throw new Error(`Runnable ${step} has no first node`); + if (currentLastNode) graph.addEdge(currentLastNode, stepFirstNode); + currentLastNode = stepGraph.lastNode(); + }); + return graph; + } + pipe(coerceable) { + if (RunnableSequence.isRunnableSequence(coerceable)) return new RunnableSequence({ + first: this.first, + middle: this.middle.concat([ + this.last, + coerceable.first, + ...coerceable.middle + ]), + last: coerceable.last, + name: this.name ?? coerceable.name + }); + else return new RunnableSequence({ + first: this.first, + middle: [...this.middle, this.last], + last: _coerceToRunnable(coerceable), + name: this.name + }); + } + static isRunnableSequence(thing) { + return Array.isArray(thing.middle) && Runnable.isRunnable(thing); + } + static from([first, ...runnables], nameOrFields) { + let extra = {}; + if (typeof nameOrFields === "string") extra.name = nameOrFields; + else if (nameOrFields !== void 0) extra = nameOrFields; + return new RunnableSequence({ + ...extra, + first: _coerceToRunnable(first), + middle: runnables.slice(0, -1).map(_coerceToRunnable), + last: _coerceToRunnable(runnables[runnables.length - 1]) + }); } - const maxTokens = getModelContextSize(modelName); - return maxTokens - numTokens; }; -const getVerbosity = () => false; /** -* Base class for language models, chains, tools. +* A runnable that runs a mapping of runnables in parallel, +* and returns a mapping of their outputs. +* @example +* ```typescript +* const mapChain = RunnableMap.from({ +* joke: PromptTemplate.fromTemplate("Tell me a joke about {topic}").pipe( +* new ChatAnthropic({}), +* ), +* poem: PromptTemplate.fromTemplate("write a 2-line poem about {topic}").pipe( +* new ChatAnthropic({}), +* ), +* }); +* const result = await mapChain.invoke({ topic: "bear" }); +* ``` */ -var BaseLangChain = class extends Runnable { - /** - * Whether to print out response text. - */ - verbose; - callbacks; - tags; - metadata; - get lc_attributes() { - return { - callbacks: void 0, - verbose: void 0 - }; +var RunnableMap = class RunnableMap extends Runnable { + static lc_name() { + return "RunnableMap"; } - constructor(params) { - super(params); - this.verbose = params.verbose ?? getVerbosity(); - this.callbacks = params.callbacks; - this.tags = params.tags ?? []; - this.metadata = params.metadata ?? {}; + lc_namespace = ["langchain_core", "runnables"]; + lc_serializable = true; + steps; + getStepsKeys() { + return Object.keys(this.steps); + } + constructor(fields) { + super(fields); + this.steps = {}; + for (const [key, value] of Object.entries(fields.steps)) this.steps[key] = _coerceToRunnable(value); + } + static from(steps) { + return new RunnableMap({ steps }); + } + async invoke(input, options) { + const config = ensureConfig(options); + const callbackManager_ = await getCallbackManagerForConfig(config); + const runManager = await callbackManager_?.handleChainStart(this.toJSON(), { input }, config.runId, void 0, void 0, void 0, config?.runName); + delete config.runId; + const output = {}; + try { + const promises = Object.entries(this.steps).map(async ([key, runnable]) => { + output[key] = await runnable.invoke(input, config_patchConfig(config, { callbacks: runManager?.getChild(`map:key:${key}`) })); + }); + await raceWithSignal(Promise.all(promises), options?.signal); + } catch (e) { + await runManager?.handleChainError(e); + throw e; + } + await runManager?.handleChainEnd(output); + return output; + } + async *_transform(generator, runManager, options) { + const steps = { ...this.steps }; + const inputCopies = atee(generator, Object.keys(steps).length); + const tasks = new Map(Object.entries(steps).map(([key, runnable], i) => { + const gen = runnable.transform(inputCopies[i], config_patchConfig(options, { callbacks: runManager?.getChild(`map:key:${key}`) })); + return [key, gen.next().then((result) => ({ + key, + gen, + result + }))]; + })); + while (tasks.size) { + const promise = Promise.race(tasks.values()); + const { key, result, gen } = await raceWithSignal(promise, options?.signal); + tasks.delete(key); + if (!result.done) { + yield { [key]: result.value }; + tasks.set(key, gen.next().then((result$1) => ({ + key, + gen, + result: result$1 + }))); + } + } + } + transform(generator, options) { + return this._transformStreamWithConfig(generator, this._transform.bind(this), options); + } + async stream(input, options) { + async function* generator() { + yield input; + } + const config = ensureConfig(options); + const wrappedGenerator = new AsyncGeneratorWithSetup({ + generator: this.transform(generator(), config), + config + }); + await wrappedGenerator.setup; + return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); } }; /** -* Base class for language models. +* A runnable that wraps a traced LangSmith function. */ -var BaseLanguageModel = class extends BaseLangChain { - /** - * Keys that the language model accepts as call options. - */ - get callKeys() { - return [ - "stop", - "timeout", - "signal", - "tags", - "metadata", - "callbacks" - ]; +var RunnableTraceable = class RunnableTraceable extends Runnable { + lc_serializable = false; + lc_namespace = ["langchain_core", "runnables"]; + func; + constructor(fields) { + super(fields); + if (!isTraceableFunction(fields.func)) throw new Error("RunnableTraceable requires a function that is wrapped in traceable higher-order function"); + this.func = fields.func; } - /** - * The async caller should be used by subclasses to make any async calls, - * which will thus benefit from the concurrency and retry logic. - */ - caller; - cache; - constructor({ callbacks, callbackManager,...params }) { - const { cache,...rest } = params; - super({ - callbacks: callbacks ?? callbackManager, - ...rest - }); - if (typeof cache === "object") this.cache = cache; - else if (cache) this.cache = InMemoryCache.global(); - else this.cache = void 0; - this.caller = new async_caller_AsyncCaller(params ?? {}); + async invoke(input, options) { + const [config] = this._getOptionsList(options ?? {}, 1); + const callbacks = await getCallbackManagerForConfig(config); + const promise = this.func(config_patchConfig(config, { callbacks }), input); + return raceWithSignal(promise, config?.signal); } - _encoding; - /** - * Get the number of tokens in the content. - * @param content The content to get the number of tokens for. - * @returns The number of tokens in the content. - */ - async getNumTokens(content) { - let textContent; - if (typeof content === "string") textContent = content; - else - /** - * Content is an array of ContentBlock - * - * ToDo(@christian-bromann): This is a temporary fix to get the number of tokens for the content. - * We need to find a better way to do this. - * @see https://github.com/langchain-ai/langchainjs/pull/8341#pullrequestreview-2933713116 - */ - textContent = content.map((item) => { - if (typeof item === "string") return item; - if (item.type === "text" && "text" in item) return item.text; - return ""; - }).join(""); - let numTokens = Math.ceil(textContent.length / 4); - if (!this._encoding) try { - this._encoding = await encodingForModel("modelName" in this ? getModelNameForTiktoken(this.modelName) : "gpt2"); - } catch (error) { - console.warn("Failed to calculate number of tokens, falling back to approximate count", error); + async *_streamIterator(input, options) { + const [config] = this._getOptionsList(options ?? {}, 1); + const result = await this.invoke(input, options); + if (isAsyncIterable(result)) { + for await (const item of result) { + config?.signal?.throwIfAborted(); + yield item; + } + return; } - if (this._encoding) try { - numTokens = this._encoding.encode(textContent).length; - } catch (error) { - console.warn("Failed to calculate number of tokens, falling back to approximate count", error); + if (isIterator(result)) { + while (true) { + config?.signal?.throwIfAborted(); + const state = result.next(); + if (state.done) break; + yield state.value; + } + return; } - return numTokens; + yield result; } - static _convertInputToPromptValue(input) { - if (typeof input === "string") return new StringPromptValue(input); - else if (Array.isArray(input)) return new ChatPromptValue(input.map(utils_coerceMessageLikeToMessage)); - else return input; + static from(func) { + return new RunnableTraceable({ func }); } - /** - * Get the identifying parameters of the LLM. - */ - _identifyingParams() { - return {}; +}; +function assertNonTraceableFunction(func) { + if (isTraceableFunction(func)) throw new Error("RunnableLambda requires a function that is not wrapped in traceable higher-order function. This shouldn't happen."); +} +/** +* A runnable that wraps an arbitrary function that takes a single argument. +* @example +* ```typescript +* import { RunnableLambda } from "@langchain/core/runnables"; +* +* const add = (input: { x: number; y: number }) => input.x + input.y; +* +* const multiply = (input: { value: number; multiplier: number }) => +* input.value * input.multiplier; +* +* // Create runnables for the functions +* const addLambda = RunnableLambda.from(add); +* const multiplyLambda = RunnableLambda.from(multiply); +* +* // Chain the lambdas for a mathematical operation +* const chainedLambda = addLambda.pipe((result) => +* multiplyLambda.invoke({ value: result, multiplier: 2 }) +* ); +* +* // Example invocation of the chainedLambda +* const result = await chainedLambda.invoke({ x: 2, y: 3 }); +* +* // Will log "10" (since (2 + 3) * 2 = 10) +* ``` +*/ +var RunnableLambda = class RunnableLambda extends Runnable { + static lc_name() { + return "RunnableLambda"; } - /** - * Create a unique cache key for a specific call to a specific language model. - * @param callOptions Call options for the model - * @returns A unique cache key. - */ - _getSerializedCacheKeyParametersForCall({ config,...callOptions }) { - const params = { - ...this._identifyingParams(), - ...callOptions, - _type: this._llmType(), - _model: this._modelType() - }; - const filteredEntries = Object.entries(params).filter(([_, value]) => value !== void 0); - const serializedEntries = filteredEntries.map(([key, value]) => `${key}:${JSON.stringify(value)}`).sort().join(","); - return serializedEntries; + lc_namespace = ["langchain_core", "runnables"]; + func; + constructor(fields) { + if (isTraceableFunction(fields.func)) return RunnableTraceable.from(fields.func); + super(fields); + assertNonTraceableFunction(fields.func); + this.func = fields.func; } - /** - * @deprecated - * Return a json-like object representing this LLM. - */ - serialize() { - return { - ...this._identifyingParams(), - _type: this._llmType(), - _model: this._modelType() - }; + static from(func) { + return new RunnableLambda({ func }); } - /** - * @deprecated - * Load an LLM from a json-like object describing it. - */ - static async deserialize(_data) { - throw new Error("Use .toJSON() instead"); + async _invoke(input, config, runManager) { + return new Promise((resolve, reject) => { + const childConfig = config_patchConfig(config, { + callbacks: runManager?.getChild(), + recursionLimit: (config?.recursionLimit ?? DEFAULT_RECURSION_LIMIT) - 1 + }); + async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(childConfig), async () => { + try { + let output = await this.func(input, { ...childConfig }); + if (output && Runnable.isRunnable(output)) { + if (config?.recursionLimit === 0) throw new Error("Recursion limit reached."); + output = await output.invoke(input, { + ...childConfig, + recursionLimit: (childConfig.recursionLimit ?? DEFAULT_RECURSION_LIMIT) - 1 + }); + } else if (isAsyncIterable(output)) { + let finalOutput; + for await (const chunk of consumeAsyncIterableInContext(childConfig, output)) { + config?.signal?.throwIfAborted(); + if (finalOutput === void 0) finalOutput = chunk; + else try { + finalOutput = this._concatOutputChunks(finalOutput, chunk); + } catch { + finalOutput = chunk; + } + } + output = finalOutput; + } else if (isIterableIterator(output)) { + let finalOutput; + for (const chunk of consumeIteratorInContext(childConfig, output)) { + config?.signal?.throwIfAborted(); + if (finalOutput === void 0) finalOutput = chunk; + else try { + finalOutput = this._concatOutputChunks(finalOutput, chunk); + } catch { + finalOutput = chunk; + } + } + output = finalOutput; + } + resolve(output); + } catch (e) { + reject(e); + } + }); + }); } - /** - * Return profiling information for the model. - * - * @returns {ModelProfile} An object describing the model's capabilities and constraints - */ - get profile() { - return {}; + async invoke(input, options) { + return this._callWithConfig(this._invoke.bind(this), input, options); + } + async *_transform(generator, runManager, config) { + let finalChunk; + for await (const chunk of generator) if (finalChunk === void 0) finalChunk = chunk; + else try { + finalChunk = this._concatOutputChunks(finalChunk, chunk); + } catch { + finalChunk = chunk; + } + const childConfig = config_patchConfig(config, { + callbacks: runManager?.getChild(), + recursionLimit: (config?.recursionLimit ?? DEFAULT_RECURSION_LIMIT) - 1 + }); + const output = await new Promise((resolve, reject) => { + async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(childConfig), async () => { + try { + const res = await this.func(finalChunk, { + ...childConfig, + config: childConfig + }); + resolve(res); + } catch (e) { + reject(e); + } + }); + }); + if (output && Runnable.isRunnable(output)) { + if (config?.recursionLimit === 0) throw new Error("Recursion limit reached."); + const stream = await output.stream(finalChunk, childConfig); + for await (const chunk of stream) yield chunk; + } else if (isAsyncIterable(output)) for await (const chunk of consumeAsyncIterableInContext(childConfig, output)) { + config?.signal?.throwIfAborted(); + yield chunk; + } + else if (isIterableIterator(output)) for (const chunk of consumeIteratorInContext(childConfig, output)) { + config?.signal?.throwIfAborted(); + yield chunk; + } + else yield output; + } + transform(generator, options) { + return this._transformStreamWithConfig(generator, this._transform.bind(this), options); + } + async stream(input, options) { + async function* generator() { + yield input; + } + const config = ensureConfig(options); + const wrappedGenerator = new AsyncGeneratorWithSetup({ + generator: this.transform(generator(), config), + config + }); + await wrappedGenerator.setup; + return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); } }; - -//#endregion - -//# sourceMappingURL=base.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/passthrough.js - - - - -//#region src/runnables/passthrough.ts /** -* A runnable to passthrough inputs unchanged or with additional keys. +* A runnable that runs a mapping of runnables in parallel, +* and returns a mapping of their outputs. +* @example +* ```typescript +* import { +* RunnableLambda, +* RunnableParallel, +* } from "@langchain/core/runnables"; +* +* const addYears = (age: number): number => age + 5; +* const yearsToFifty = (age: number): number => 50 - age; +* const yearsToHundred = (age: number): number => 100 - age; +* +* const addYearsLambda = RunnableLambda.from(addYears); +* const milestoneFiftyLambda = RunnableLambda.from(yearsToFifty); +* const milestoneHundredLambda = RunnableLambda.from(yearsToHundred); +* +* // Pipe will coerce objects into RunnableParallel by default, but we +* // explicitly instantiate one here to demonstrate +* const sequence = addYearsLambda.pipe( +* RunnableParallel.from({ +* years_to_fifty: milestoneFiftyLambda, +* years_to_hundred: milestoneHundredLambda, +* }) +* ); +* +* // Invoke the sequence with a single age input +* const res = await sequence.invoke(25); +* +* // { years_to_fifty: 20, years_to_hundred: 70 } +* ``` +*/ +var RunnableParallel = class extends RunnableMap {}; +/** +* A Runnable that can fallback to other Runnables if it fails. +* External APIs (e.g., APIs for a language model) may at times experience +* degraded performance or even downtime. * -* This runnable behaves almost like the identity function, except that it -* can be configured to add additional keys to the output, if the input is -* an object. +* In these cases, it can be useful to have a fallback Runnable that can be +* used in place of the original Runnable (e.g., fallback to another LLM provider). * -* The example below demonstrates how to use `RunnablePassthrough to -* passthrough the input from the `.invoke()` +* Fallbacks can be defined at the level of a single Runnable, or at the level +* of a chain of Runnables. Fallbacks are tried in order until one succeeds or +* all fail. +* +* While you can instantiate a `RunnableWithFallbacks` directly, it is usually +* more convenient to use the `withFallbacks` method on an existing Runnable. +* +* When streaming, fallbacks will only be called on failures during the initial +* stream creation. Errors that occur after a stream starts will not fallback +* to the next Runnable. * * @example * ```typescript -* const chain = RunnableSequence.from([ -* { -* question: new RunnablePassthrough(), -* context: async () => loadContextFromStore(), -* }, -* prompt, -* llm, -* outputParser, -* ]); -* const response = await chain.invoke( -* "I can pass a single string instead of an object since I'm using `RunnablePassthrough`." -* ); +* import { +* RunnableLambda, +* RunnableWithFallbacks, +* } from "@langchain/core/runnables"; +* +* const primaryOperation = (input: string): string => { +* if (input !== "safe") { +* throw new Error("Primary operation failed due to unsafe input"); +* } +* return `Processed: ${input}`; +* }; +* +* // Define a fallback operation that processes the input differently +* const fallbackOperation = (input: string): string => +* `Fallback processed: ${input}`; +* +* const primaryRunnable = RunnableLambda.from(primaryOperation); +* const fallbackRunnable = RunnableLambda.from(fallbackOperation); +* +* // Apply the fallback logic using the .withFallbacks() method +* const runnableWithFallback = primaryRunnable.withFallbacks([fallbackRunnable]); +* +* // Alternatively, create a RunnableWithFallbacks instance manually +* const manualFallbackChain = new RunnableWithFallbacks({ +* runnable: primaryRunnable, +* fallbacks: [fallbackRunnable], +* }); +* +* // Example invocation using .withFallbacks() +* const res = await runnableWithFallback +* .invoke("unsafe input") +* .catch((error) => { +* console.error("Failed after all attempts:", error.message); +* }); +* +* // "Fallback processed: unsafe input" +* +* // Example invocation using manual instantiation +* const res = await manualFallbackChain +* .invoke("safe") +* .catch((error) => { +* console.error("Failed after all attempts:", error.message); +* }); +* +* // "Processed: safe" * ``` */ -var RunnablePassthrough = class extends Runnable { +var RunnableWithFallbacks = class extends Runnable { static lc_name() { - return "RunnablePassthrough"; + return "RunnableWithFallbacks"; } lc_namespace = ["langchain_core", "runnables"]; lc_serializable = true; - func; + runnable; + fallbacks; constructor(fields) { super(fields); - if (fields) this.func = fields.func; + this.runnable = fields.runnable; + this.fallbacks = fields.fallbacks; } - async invoke(input, options) { - const config = ensureConfig(options); - if (this.func) await this.func(input, config); - return this._callWithConfig((input$1) => Promise.resolve(input$1), input, config); + *runnables() { + yield this.runnable; + for (const fallback of this.fallbacks) yield fallback; } - async *transform(generator, options) { + async invoke(input, options) { const config = ensureConfig(options); - let finalOutput; - let finalOutputSupported = true; - for await (const chunk of this._transformStreamWithConfig(generator, (input) => input, config)) { - yield chunk; - if (finalOutputSupported) if (finalOutput === void 0) finalOutput = chunk; - else try { - finalOutput = concat(finalOutput, chunk); - } catch { - finalOutput = void 0; - finalOutputSupported = false; - } - } - if (this.func && finalOutput !== void 0) await this.func(finalOutput, config); - } - /** - * A runnable that assigns key-value pairs to the input. - * - * The example below shows how you could use it with an inline function. - * - * @example - * ```typescript - * const prompt = - * PromptTemplate.fromTemplate(`Write a SQL query to answer the question using the following schema: {schema} - * Question: {question} - * SQL Query:`); - * - * // The `RunnablePassthrough.assign()` is used here to passthrough the input from the `.invoke()` - * // call (in this example it's the question), along with any inputs passed to the `.assign()` method. - * // In this case, we're passing the schema. - * const sqlQueryGeneratorChain = RunnableSequence.from([ - * RunnablePassthrough.assign({ - * schema: async () => db.getTableInfo(), - * }), - * prompt, - * new ChatOpenAI({ model: "gpt-4o-mini" }).withConfig({ stop: ["\nSQLResult:"] }), - * new StringOutputParser(), - * ]); - * const result = await sqlQueryGeneratorChain.invoke({ - * question: "How many employees are there?", - * }); - * ``` - */ - static assign(mapping) { - return new RunnableAssign(new RunnableMap({ steps: mapping })); - } -}; - -//#endregion - -//# sourceMappingURL=passthrough.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/utils.js -//#region src/language_models/utils.ts -const language_models_utils_iife = (fn) => fn(); -function castStandardMessageContent(message) { - const Cls = message.constructor; - return new Cls({ - ...message, - content: message.contentBlocks, - response_metadata: { - ...message.response_metadata, - output_version: "v1" - } - }); -} - -//#endregion - -//# sourceMappingURL=utils.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/chat_models.js - - - - - - - - - - - - - - - - - - -//#region src/language_models/chat_models.ts -var chat_models_exports = {}; -__export(chat_models_exports, { - BaseChatModel: () => BaseChatModel, - SimpleChatModel: () => SimpleChatModel -}); -function _formatForTracing(messages) { - const messagesToTrace = []; - for (const message of messages) { - let messageToTrace = message; - if (Array.isArray(message.content)) for (let idx = 0; idx < message.content.length; idx++) { - const block = message.content[idx]; - if (isURLContentBlock(block) || isBase64ContentBlock(block)) { - if (messageToTrace === message) messageToTrace = new message.constructor({ - ...messageToTrace, - content: [ - ...message.content.slice(0, idx), - convertToOpenAIImageBlock(block), - ...message.content.slice(idx + 1) - ] - }); + const callbackManager_ = await getCallbackManagerForConfig(config); + const { runId,...otherConfigFields } = config; + const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), runId, void 0, void 0, void 0, otherConfigFields?.runName); + const childConfig = config_patchConfig(otherConfigFields, { callbacks: runManager?.getChild() }); + const res = await async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(childConfig, async () => { + let firstError; + for (const runnable of this.runnables()) { + config?.signal?.throwIfAborted(); + try { + const output = await runnable.invoke(input, childConfig); + await runManager?.handleChainEnd(base_coerceToDict(output, "output")); + return output; + } catch (e) { + if (firstError === void 0) firstError = e; + } } - } - messagesToTrace.push(messageToTrace); - } - return messagesToTrace; -} -/** -* Base class for chat models. It extends the BaseLanguageModel class and -* provides methods for generating chat based on input messages. -*/ -var BaseChatModel = class BaseChatModel extends BaseLanguageModel { - lc_namespace = [ - "langchain", - "chat_models", - this._llmType() - ]; - disableStreaming = false; - outputVersion; - get callKeys() { - return [...super.callKeys, "outputVersion"]; - } - constructor(fields) { - super(fields); - this.outputVersion = language_models_utils_iife(() => { - const outputVersion = fields.outputVersion ?? getEnvironmentVariable("LC_OUTPUT_VERSION"); - if (outputVersion && ["v0", "v1"].includes(outputVersion)) return outputVersion; - return "v0"; + if (firstError === void 0) throw new Error("No error stored at end of fallback."); + await runManager?.handleChainError(firstError); + throw firstError; }); - } - _separateRunnableConfigFromCallOptionsCompat(options) { - const [runnableConfig, callOptions] = super._separateRunnableConfigFromCallOptions(options); - callOptions.signal = runnableConfig.signal; - return [runnableConfig, callOptions]; - } - /** - * Invokes the chat model with a single input. - * @param input The input for the language model. - * @param options The call options. - * @returns A Promise that resolves to a BaseMessageChunk. - */ - async invoke(input, options) { - const promptValue = BaseChatModel._convertInputToPromptValue(input); - const result = await this.generatePrompt([promptValue], options, options?.callbacks); - const chatGeneration = result.generations[0][0]; - return chatGeneration.message; - } - async *_streamResponseChunks(_messages, _options, _runManager) { - throw new Error("Not implemented."); + return res; } async *_streamIterator(input, options) { - if (this._streamResponseChunks === BaseChatModel.prototype._streamResponseChunks || this.disableStreaming) yield this.invoke(input, options); - else { - const prompt = BaseChatModel._convertInputToPromptValue(input); - const messages = prompt.toChatMessages(); - const [runnableConfig, callOptions] = this._separateRunnableConfigFromCallOptionsCompat(options); - const inheritableMetadata = { - ...runnableConfig.metadata, - ...this.getLsParams(callOptions) - }; - const callbackManager_ = await CallbackManager.configure(runnableConfig.callbacks, this.callbacks, runnableConfig.tags, this.tags, inheritableMetadata, this.metadata, { verbose: this.verbose }); - const extra = { - options: callOptions, - invocation_params: this?.invocationParams(callOptions), - batch_size: 1 - }; - const outputVersion = callOptions.outputVersion ?? this.outputVersion; - const runManagers = await callbackManager_?.handleChatModelStart(this.toJSON(), [_formatForTracing(messages)], runnableConfig.runId, void 0, extra, void 0, void 0, runnableConfig.runName); - let generationChunk; - let llmOutput; + const config = ensureConfig(options); + const callbackManager_ = await getCallbackManagerForConfig(config); + const { runId,...otherConfigFields } = config; + const runManager = await callbackManager_?.handleChainStart(this.toJSON(), base_coerceToDict(input, "input"), runId, void 0, void 0, void 0, otherConfigFields?.runName); + let firstError; + let stream; + for (const runnable of this.runnables()) { + config?.signal?.throwIfAborted(); + const childConfig = config_patchConfig(otherConfigFields, { callbacks: runManager?.getChild() }); try { - for await (const chunk of this._streamResponseChunks(messages, callOptions, runManagers?.[0])) { - if (chunk.message.id == null) { - const runId = runManagers?.at(0)?.runId; - if (runId != null) chunk.message._updateId(`run-${runId}`); - } - chunk.message.response_metadata = { - ...chunk.generationInfo, - ...chunk.message.response_metadata - }; - if (outputVersion === "v1") yield castStandardMessageContent(chunk.message); - else yield chunk.message; - if (!generationChunk) generationChunk = chunk; - else generationChunk = generationChunk.concat(chunk); - if (isAIMessageChunk(chunk.message) && chunk.message.usage_metadata !== void 0) llmOutput = { tokenUsage: { - promptTokens: chunk.message.usage_metadata.input_tokens, - completionTokens: chunk.message.usage_metadata.output_tokens, - totalTokens: chunk.message.usage_metadata.total_tokens - } }; - } - } catch (err) { - await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMError(err))); - throw err; + const originalStream = await runnable.stream(input, childConfig); + stream = consumeAsyncIterableInContext(childConfig, originalStream); + break; + } catch (e) { + if (firstError === void 0) firstError = e; } - await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMEnd({ - generations: [[generationChunk]], - llmOutput - }))); } - } - getLsParams(options) { - const providerName = this.getName().startsWith("Chat") ? this.getName().replace("Chat", "") : this.getName(); - return { - ls_model_type: "chat", - ls_stop: options.stop, - ls_provider: providerName - }; - } - /** @ignore */ - async _generateUncached(messages, parsedOptions, handledOptions, startedRunManagers) { - const baseMessages = messages.map((messageList) => messageList.map(utils_coerceMessageLikeToMessage)); - let runManagers; - if (startedRunManagers !== void 0 && startedRunManagers.length === baseMessages.length) runManagers = startedRunManagers; - else { - const inheritableMetadata = { - ...handledOptions.metadata, - ...this.getLsParams(parsedOptions) - }; - const callbackManager_ = await CallbackManager.configure(handledOptions.callbacks, this.callbacks, handledOptions.tags, this.tags, inheritableMetadata, this.metadata, { verbose: this.verbose }); - const extra = { - options: parsedOptions, - invocation_params: this?.invocationParams(parsedOptions), - batch_size: 1 - }; - runManagers = await callbackManager_?.handleChatModelStart(this.toJSON(), baseMessages.map(_formatForTracing), handledOptions.runId, void 0, extra, void 0, void 0, handledOptions.runName); + if (stream === void 0) { + const error = firstError ?? /* @__PURE__ */ new Error("No error stored at end of fallback."); + await runManager?.handleChainError(error); + throw error; } - const outputVersion = parsedOptions.outputVersion ?? this.outputVersion; - const generations = []; - const llmOutputs = []; - const hasStreamingHandler = !!runManagers?.[0].handlers.find(callbackHandlerPrefersStreaming); - if (hasStreamingHandler && !this.disableStreaming && baseMessages.length === 1 && this._streamResponseChunks !== BaseChatModel.prototype._streamResponseChunks) try { - const stream = await this._streamResponseChunks(baseMessages[0], parsedOptions, runManagers?.[0]); - let aggregated; - let llmOutput; + let output; + try { for await (const chunk of stream) { - if (chunk.message.id == null) { - const runId = runManagers?.at(0)?.runId; - if (runId != null) chunk.message._updateId(`run-${runId}`); + yield chunk; + try { + output = output === void 0 ? output : this._concatOutputChunks(output, chunk); + } catch { + output = void 0; } - if (aggregated === void 0) aggregated = chunk; - else aggregated = concat(aggregated, chunk); - if (isAIMessageChunk(chunk.message) && chunk.message.usage_metadata !== void 0) llmOutput = { tokenUsage: { - promptTokens: chunk.message.usage_metadata.input_tokens, - completionTokens: chunk.message.usage_metadata.output_tokens, - totalTokens: chunk.message.usage_metadata.total_tokens - } }; } - if (aggregated === void 0) throw new Error("Received empty response from chat model call."); - generations.push([aggregated]); - await runManagers?.[0].handleLLMEnd({ - generations, - llmOutput - }); } catch (e) { - await runManagers?.[0].handleLLMError(e); + await runManager?.handleChainError(e); throw e; } - else { - const results = await Promise.allSettled(baseMessages.map(async (messageList, i) => { - const generateResults = await this._generate(messageList, { - ...parsedOptions, - promptIndex: i - }, runManagers?.[i]); - if (outputVersion === "v1") for (const generation of generateResults.generations) generation.message = castStandardMessageContent(generation.message); - return generateResults; - })); - await Promise.all(results.map(async (pResult, i) => { - if (pResult.status === "fulfilled") { - const result = pResult.value; - for (const generation of result.generations) { - if (generation.message.id == null) { - const runId = runManagers?.at(0)?.runId; - if (runId != null) generation.message._updateId(`run-${runId}`); - } - generation.message.response_metadata = { - ...generation.generationInfo, - ...generation.message.response_metadata - }; - } - if (result.generations.length === 1) result.generations[0].message.response_metadata = { - ...result.llmOutput, - ...result.generations[0].message.response_metadata - }; - generations[i] = result.generations; - llmOutputs[i] = result.llmOutput; - return runManagers?.[i]?.handleLLMEnd({ - generations: [result.generations], - llmOutput: result.llmOutput - }); - } else { - await runManagers?.[i]?.handleLLMError(pResult.reason); - return Promise.reject(pResult.reason); - } - })); - } - const output = { - generations, - llmOutput: llmOutputs.length ? this._combineLLMOutput?.(...llmOutputs) : void 0 - }; - Object.defineProperty(output, RUN_KEY, { - value: runManagers ? { runIds: runManagers?.map((manager) => manager.runId) } : void 0, - configurable: true - }); - return output; + await runManager?.handleChainEnd(base_coerceToDict(output, "output")); } - async _generateCached({ messages, cache, llmStringKey, parsedOptions, handledOptions }) { - const baseMessages = messages.map((messageList) => messageList.map(utils_coerceMessageLikeToMessage)); - const inheritableMetadata = { - ...handledOptions.metadata, - ...this.getLsParams(parsedOptions) - }; - const callbackManager_ = await CallbackManager.configure(handledOptions.callbacks, this.callbacks, handledOptions.tags, this.tags, inheritableMetadata, this.metadata, { verbose: this.verbose }); - const extra = { - options: parsedOptions, - invocation_params: this?.invocationParams(parsedOptions), - batch_size: 1 - }; - const runManagers = await callbackManager_?.handleChatModelStart(this.toJSON(), baseMessages.map(_formatForTracing), handledOptions.runId, void 0, extra, void 0, void 0, handledOptions.runName); - const missingPromptIndices = []; - const results = await Promise.allSettled(baseMessages.map(async (baseMessage, index) => { - const prompt = BaseChatModel._convertInputToPromptValue(baseMessage).toString(); - const result = await cache.lookup(prompt, llmStringKey); - if (result == null) missingPromptIndices.push(index); - return result; + async batch(inputs, options, batchOptions) { + if (batchOptions?.returnExceptions) throw new Error("Not implemented."); + const configList = this._getOptionsList(options ?? {}, inputs.length); + const callbackManagers = await Promise.all(configList.map((config) => getCallbackManagerForConfig(config))); + const runManagers = await Promise.all(callbackManagers.map(async (callbackManager, i) => { + const handleStartRes = await callbackManager?.handleChainStart(this.toJSON(), base_coerceToDict(inputs[i], "input"), configList[i].runId, void 0, void 0, void 0, configList[i].runName); + delete configList[i].runId; + return handleStartRes; })); - const cachedResults = results.map((result, index) => ({ - result, - runManager: runManagers?.[index] - })).filter(({ result }) => result.status === "fulfilled" && result.value != null || result.status === "rejected"); - const outputVersion = parsedOptions.outputVersion ?? this.outputVersion; - const generations = []; - await Promise.all(cachedResults.map(async ({ result: promiseResult, runManager }, i) => { - if (promiseResult.status === "fulfilled") { - const result = promiseResult.value; - generations[i] = result.map((result$1) => { - if ("message" in result$1 && isBaseMessage(result$1.message) && isAIMessage(result$1.message)) { - result$1.message.usage_metadata = { - input_tokens: 0, - output_tokens: 0, - total_tokens: 0 - }; - if (outputVersion === "v1") result$1.message = castStandardMessageContent(result$1.message); - } - result$1.generationInfo = { - ...result$1.generationInfo, - tokenUsage: {} - }; - return result$1; - }); - if (result.length) await runManager?.handleLLMNewToken(result[0].text); - return runManager?.handleLLMEnd({ generations: [result] }, void 0, void 0, void 0, { cached: true }); - } else { - await runManager?.handleLLMError(promiseResult.reason, void 0, void 0, void 0, { cached: true }); - return Promise.reject(promiseResult.reason); + let firstError; + for (const runnable of this.runnables()) { + configList[0].signal?.throwIfAborted(); + try { + const outputs = await runnable.batch(inputs, runManagers.map((runManager, j) => config_patchConfig(configList[j], { callbacks: runManager?.getChild() })), batchOptions); + await Promise.all(runManagers.map((runManager, i) => runManager?.handleChainEnd(base_coerceToDict(outputs[i], "output")))); + return outputs; + } catch (e) { + if (firstError === void 0) firstError = e; } - })); - const output = { - generations, - missingPromptIndices, - startedRunManagers: runManagers - }; - Object.defineProperty(output, RUN_KEY, { - value: runManagers ? { runIds: runManagers?.map((manager) => manager.runId) } : void 0, - configurable: true - }); - return output; - } - /** - * Generates chat based on the input messages. - * @param messages An array of arrays of BaseMessage instances. - * @param options The call options or an array of stop sequences. - * @param callbacks The callbacks for the language model. - * @returns A Promise that resolves to an LLMResult. - */ - async generate(messages, options, callbacks) { - let parsedOptions; - if (Array.isArray(options)) parsedOptions = { stop: options }; - else parsedOptions = options; - const baseMessages = messages.map((messageList) => messageList.map(utils_coerceMessageLikeToMessage)); - const [runnableConfig, callOptions] = this._separateRunnableConfigFromCallOptionsCompat(parsedOptions); - runnableConfig.callbacks = runnableConfig.callbacks ?? callbacks; - if (!this.cache) return this._generateUncached(baseMessages, callOptions, runnableConfig); - const { cache } = this; - const llmStringKey = this._getSerializedCacheKeyParametersForCall(callOptions); - const { generations, missingPromptIndices, startedRunManagers } = await this._generateCached({ - messages: baseMessages, - cache, - llmStringKey, - parsedOptions: callOptions, - handledOptions: runnableConfig - }); - let llmOutput = {}; - if (missingPromptIndices.length > 0) { - const results = await this._generateUncached(missingPromptIndices.map((i) => baseMessages[i]), callOptions, runnableConfig, startedRunManagers !== void 0 ? missingPromptIndices.map((i) => startedRunManagers?.[i]) : void 0); - await Promise.all(results.generations.map(async (generation, index) => { - const promptIndex = missingPromptIndices[index]; - generations[promptIndex] = generation; - const prompt = BaseChatModel._convertInputToPromptValue(baseMessages[promptIndex]).toString(); - return cache.update(prompt, llmStringKey, generation); - })); - llmOutput = results.llmOutput ?? {}; } + if (!firstError) throw new Error("No error stored at end of fallbacks."); + await Promise.all(runManagers.map((runManager) => runManager?.handleChainError(firstError))); + throw firstError; + } +}; +function _coerceToRunnable(coerceable) { + if (typeof coerceable === "function") return new RunnableLambda({ func: coerceable }); + else if (Runnable.isRunnable(coerceable)) return coerceable; + else if (!Array.isArray(coerceable) && typeof coerceable === "object") { + const runnables = {}; + for (const [key, value] of Object.entries(coerceable)) runnables[key] = _coerceToRunnable(value); + return new RunnableMap({ steps: runnables }); + } else throw new Error(`Expected a Runnable, function or object.\nInstead got an unsupported type.`); +} +/** +* A runnable that assigns key-value pairs to inputs of type `Record`. +* @example +* ```typescript +* import { +* RunnableAssign, +* RunnableLambda, +* RunnableParallel, +* } from "@langchain/core/runnables"; +* +* const calculateAge = (x: { birthYear: number }): { age: number } => { +* const currentYear = new Date().getFullYear(); +* return { age: currentYear - x.birthYear }; +* }; +* +* const createGreeting = (x: { name: string }): { greeting: string } => { +* return { greeting: `Hello, ${x.name}!` }; +* }; +* +* const mapper = RunnableParallel.from({ +* age_step: RunnableLambda.from(calculateAge), +* greeting_step: RunnableLambda.from(createGreeting), +* }); +* +* const runnableAssign = new RunnableAssign({ mapper }); +* +* const res = await runnableAssign.invoke({ name: "Alice", birthYear: 1990 }); +* +* // { name: "Alice", birthYear: 1990, age_step: { age: 34 }, greeting_step: { greeting: "Hello, Alice!" } } +* ``` +*/ +var RunnableAssign = class extends Runnable { + static lc_name() { + return "RunnableAssign"; + } + lc_namespace = ["langchain_core", "runnables"]; + lc_serializable = true; + mapper; + constructor(fields) { + if (fields instanceof RunnableMap) fields = { mapper: fields }; + super(fields); + this.mapper = fields.mapper; + } + async invoke(input, options) { + const mapperResult = await this.mapper.invoke(input, options); return { - generations, - llmOutput + ...input, + ...mapperResult }; } - /** - * Get the parameters used to invoke the model - */ - invocationParams(_options) { - return {}; - } - _modelType() { - return "base_chat_model"; + async *_transform(generator, runManager, options) { + const mapperKeys = this.mapper.getStepsKeys(); + const [forPassthrough, forMapper] = atee(generator); + const mapperOutput = this.mapper.transform(forMapper, config_patchConfig(options, { callbacks: runManager?.getChild() })); + const firstMapperChunkPromise = mapperOutput.next(); + for await (const chunk of forPassthrough) { + if (typeof chunk !== "object" || Array.isArray(chunk)) throw new Error(`RunnableAssign can only be used with objects as input, got ${typeof chunk}`); + const filtered = Object.fromEntries(Object.entries(chunk).filter(([key]) => !mapperKeys.includes(key))); + if (Object.keys(filtered).length > 0) yield filtered; + } + yield (await firstMapperChunkPromise).value; + for await (const chunk of mapperOutput) yield chunk; } - /** - * Generates a prompt based on the input prompt values. - * @param promptValues An array of BasePromptValue instances. - * @param options The call options or an array of stop sequences. - * @param callbacks The callbacks for the language model. - * @returns A Promise that resolves to an LLMResult. - */ - async generatePrompt(promptValues, options, callbacks) { - const promptMessages = promptValues.map((promptValue) => promptValue.toChatMessages()); - return this.generate(promptMessages, options, callbacks); + transform(generator, options) { + return this._transformStreamWithConfig(generator, this._transform.bind(this), options); } - withStructuredOutput(outputSchema, config) { - if (typeof this.bindTools !== "function") throw new Error(`Chat model must implement ".bindTools()" to use withStructuredOutput.`); - if (config?.strict) throw new Error(`"strict" mode is not supported for this model by default.`); - const schema = outputSchema; - const name = config?.name; - const description = getSchemaDescription(schema) ?? "A function available to call."; - const method = config?.method; - const includeRaw = config?.includeRaw; - if (method === "jsonMode") throw new Error(`Base withStructuredOutput implementation only supports "functionCalling" as a method.`); - let functionName = name ?? "extract"; - let tools; - if (isInteropZodSchema(schema)) tools = [{ - type: "function", - function: { - name: functionName, - description, - parameters: toJsonSchema(schema) - } - }]; - else { - if ("name" in schema) functionName = schema.name; - tools = [{ - type: "function", - function: { - name: functionName, - description, - parameters: schema - } - }]; + async stream(input, options) { + async function* generator() { + yield input; } - const llm = this.bindTools(tools); - const outputParser = RunnableLambda.from((input) => { - if (!AIMessageChunk.isInstance(input)) throw new Error("Input is not an AIMessageChunk."); - if (!input.tool_calls || input.tool_calls.length === 0) throw new Error("No tool calls found in the response."); - const toolCall = input.tool_calls.find((tc) => tc.name === functionName); - if (!toolCall) throw new Error(`No tool call found with name ${functionName}.`); - return toolCall.args; + const config = ensureConfig(options); + const wrappedGenerator = new AsyncGeneratorWithSetup({ + generator: this.transform(generator(), config), + config }); - if (!includeRaw) return llm.pipe(outputParser).withConfig({ runName: "StructuredOutput" }); - const parserAssign = RunnablePassthrough.assign({ parsed: (input, config$1) => outputParser.invoke(input.raw, config$1) }); - const parserNone = RunnablePassthrough.assign({ parsed: () => null }); - const parsedWithFallback = parserAssign.withFallbacks({ fallbacks: [parserNone] }); - return RunnableSequence.from([{ raw: llm }, parsedWithFallback]).withConfig({ runName: "StructuredOutputRunnable" }); - } -}; -/** -* An abstract class that extends BaseChatModel and provides a simple -* implementation of _generate. -*/ -var SimpleChatModel = class extends BaseChatModel { - async _generate(messages, options, runManager) { - const text = await this._call(messages, options, runManager); - const message = new AIMessage(text); - if (typeof message.content !== "string") throw new Error("Cannot generate with a simple chat model when output is not a string."); - return { generations: [{ - text: message.content, - message - }] }; + await wrappedGenerator.setup; + return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); } }; - -//#endregion - -//# sourceMappingURL=chat_models.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/llms.js - - - - - - - -//#region src/language_models/llms.ts -var llms_exports = {}; -__export(llms_exports, { - BaseLLM: () => BaseLLM, - LLM: () => LLM -}); /** -* LLM Wrapper. Takes in a prompt (or prompts) and returns a string. +* A runnable that assigns key-value pairs to inputs of type `Record`. +* Useful for streaming, can be automatically created and chained by calling `runnable.pick();`. +* @example +* ```typescript +* import { RunnablePick } from "@langchain/core/runnables"; +* +* const inputData = { +* name: "John", +* age: 30, +* city: "New York", +* country: "USA", +* email: "john.doe@example.com", +* phone: "+1234567890", +* }; +* +* const basicInfoRunnable = new RunnablePick(["name", "city"]); +* +* // Example invocation +* const res = await basicInfoRunnable.invoke(inputData); +* +* // { name: 'John', city: 'New York' } +* ``` */ -var BaseLLM = class BaseLLM extends BaseLanguageModel { - lc_namespace = [ - "langchain", - "llms", - this._llmType() - ]; - /** - * This method takes an input and options, and returns a string. It - * converts the input to a prompt value and generates a result based on - * the prompt. - * @param input Input for the LLM. - * @param options Options for the LLM call. - * @returns A string result based on the prompt. - */ - async invoke(input, options) { - const promptValue = BaseLLM._convertInputToPromptValue(input); - const result = await this.generatePrompt([promptValue], options, options?.callbacks); - return result.generations[0][0].text; - } - async *_streamResponseChunks(_input, _options, _runManager) { - throw new Error("Not implemented."); +var RunnablePick = class extends Runnable { + static lc_name() { + return "RunnablePick"; } - _separateRunnableConfigFromCallOptionsCompat(options) { - const [runnableConfig, callOptions] = super._separateRunnableConfigFromCallOptions(options); - callOptions.signal = runnableConfig.signal; - return [runnableConfig, callOptions]; + lc_namespace = ["langchain_core", "runnables"]; + lc_serializable = true; + keys; + constructor(fields) { + if (typeof fields === "string" || Array.isArray(fields)) fields = { keys: fields }; + super(fields); + this.keys = fields.keys; } - async *_streamIterator(input, options) { - if (this._streamResponseChunks === BaseLLM.prototype._streamResponseChunks) yield this.invoke(input, options); + async _pick(input) { + if (typeof this.keys === "string") return input[this.keys]; else { - const prompt = BaseLLM._convertInputToPromptValue(input); - const [runnableConfig, callOptions] = this._separateRunnableConfigFromCallOptionsCompat(options); - const callbackManager_ = await CallbackManager.configure(runnableConfig.callbacks, this.callbacks, runnableConfig.tags, this.tags, runnableConfig.metadata, this.metadata, { verbose: this.verbose }); - const extra = { - options: callOptions, - invocation_params: this?.invocationParams(callOptions), - batch_size: 1 - }; - const runManagers = await callbackManager_?.handleLLMStart(this.toJSON(), [prompt.toString()], runnableConfig.runId, void 0, extra, void 0, void 0, runnableConfig.runName); - let generation = new GenerationChunk({ text: "" }); - try { - for await (const chunk of this._streamResponseChunks(prompt.toString(), callOptions, runManagers?.[0])) { - if (!generation) generation = chunk; - else generation = generation.concat(chunk); - if (typeof chunk.text === "string") yield chunk.text; - } - } catch (err) { - await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMError(err))); - throw err; - } - await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMEnd({ generations: [[generation]] }))); + const picked = this.keys.map((key) => [key, input[key]]).filter((v) => v[1] !== void 0); + return picked.length === 0 ? void 0 : Object.fromEntries(picked); } } - /** - * This method takes prompt values, options, and callbacks, and generates - * a result based on the prompts. - * @param promptValues Prompt values for the LLM. - * @param options Options for the LLM call. - * @param callbacks Callbacks for the LLM call. - * @returns An LLMResult based on the prompts. - */ - async generatePrompt(promptValues, options, callbacks) { - const prompts = promptValues.map((promptValue) => promptValue.toString()); - return this.generate(prompts, options, callbacks); - } - /** - * Get the parameters used to invoke the model - */ - invocationParams(_options) { - return {}; + async invoke(input, options) { + return this._callWithConfig(this._pick.bind(this), input, options); } - _flattenLLMResult(llmResult) { - const llmResults = []; - for (let i = 0; i < llmResult.generations.length; i += 1) { - const genList = llmResult.generations[i]; - if (i === 0) llmResults.push({ - generations: [genList], - llmOutput: llmResult.llmOutput - }); - else { - const llmOutput = llmResult.llmOutput ? { - ...llmResult.llmOutput, - tokenUsage: {} - } : void 0; - llmResults.push({ - generations: [genList], - llmOutput - }); - } + async *_transform(generator) { + for await (const chunk of generator) { + const picked = await this._pick(chunk); + if (picked !== void 0) yield picked; } - return llmResults; } - /** @ignore */ - async _generateUncached(prompts, parsedOptions, handledOptions, startedRunManagers) { - let runManagers; - if (startedRunManagers !== void 0 && startedRunManagers.length === prompts.length) runManagers = startedRunManagers; - else { - const callbackManager_ = await CallbackManager.configure(handledOptions.callbacks, this.callbacks, handledOptions.tags, this.tags, handledOptions.metadata, this.metadata, { verbose: this.verbose }); - const extra = { - options: parsedOptions, - invocation_params: this?.invocationParams(parsedOptions), - batch_size: prompts.length - }; - runManagers = await callbackManager_?.handleLLMStart(this.toJSON(), prompts, handledOptions.runId, void 0, extra, void 0, void 0, handledOptions?.runName); - } - const hasStreamingHandler = !!runManagers?.[0].handlers.find(callbackHandlerPrefersStreaming); - let output; - if (hasStreamingHandler && prompts.length === 1 && this._streamResponseChunks !== BaseLLM.prototype._streamResponseChunks) try { - const stream = await this._streamResponseChunks(prompts[0], parsedOptions, runManagers?.[0]); - let aggregated; - for await (const chunk of stream) if (aggregated === void 0) aggregated = chunk; - else aggregated = concat(aggregated, chunk); - if (aggregated === void 0) throw new Error("Received empty response from chat model call."); - output = { - generations: [[aggregated]], - llmOutput: {} - }; - await runManagers?.[0].handleLLMEnd(output); - } catch (e) { - await runManagers?.[0].handleLLMError(e); - throw e; - } - else { - try { - output = await this._generate(prompts, parsedOptions, runManagers?.[0]); - } catch (err) { - await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMError(err))); - throw err; - } - const flattenedOutputs = this._flattenLLMResult(output); - await Promise.all((runManagers ?? []).map((runManager, i) => runManager?.handleLLMEnd(flattenedOutputs[i]))); + transform(generator, options) { + return this._transformStreamWithConfig(generator, this._transform.bind(this), options); + } + async stream(input, options) { + async function* generator() { + yield input; } - const runIds = runManagers?.map((manager) => manager.runId) || void 0; - Object.defineProperty(output, RUN_KEY, { - value: runIds ? { runIds } : void 0, - configurable: true + const config = ensureConfig(options); + const wrappedGenerator = new AsyncGeneratorWithSetup({ + generator: this.transform(generator(), config), + config }); - return output; + await wrappedGenerator.setup; + return IterableReadableStream.fromAsyncGenerator(wrappedGenerator); } - async _generateCached({ prompts, cache, llmStringKey, parsedOptions, handledOptions, runId }) { - const callbackManager_ = await CallbackManager.configure(handledOptions.callbacks, this.callbacks, handledOptions.tags, this.tags, handledOptions.metadata, this.metadata, { verbose: this.verbose }); - const extra = { - options: parsedOptions, - invocation_params: this?.invocationParams(parsedOptions), - batch_size: prompts.length - }; - const runManagers = await callbackManager_?.handleLLMStart(this.toJSON(), prompts, runId, void 0, extra, void 0, void 0, handledOptions?.runName); - const missingPromptIndices = []; - const results = await Promise.allSettled(prompts.map(async (prompt, index) => { - const result = await cache.lookup(prompt, llmStringKey); - if (result == null) missingPromptIndices.push(index); - return result; - })); - const cachedResults = results.map((result, index) => ({ - result, - runManager: runManagers?.[index] - })).filter(({ result }) => result.status === "fulfilled" && result.value != null || result.status === "rejected"); - const generations = []; - await Promise.all(cachedResults.map(async ({ result: promiseResult, runManager }, i) => { - if (promiseResult.status === "fulfilled") { - const result = promiseResult.value; - generations[i] = result.map((result$1) => { - result$1.generationInfo = { - ...result$1.generationInfo, - tokenUsage: {} - }; - return result$1; - }); - if (result.length) await runManager?.handleLLMNewToken(result[0].text); - return runManager?.handleLLMEnd({ generations: [result] }, void 0, void 0, void 0, { cached: true }); - } else { - await runManager?.handleLLMError(promiseResult.reason, void 0, void 0, void 0, { cached: true }); - return Promise.reject(promiseResult.reason); +}; +var RunnableToolLike = class extends RunnableBinding { + name; + description; + schema; + constructor(fields) { + const sequence = RunnableSequence.from([RunnableLambda.from(async (input) => { + let toolInput; + if (_isToolCall(input)) try { + toolInput = await interopParseAsync(this.schema, input.args); + } catch { + throw new ToolInputParsingException(`Received tool input did not match expected schema`, JSON.stringify(input.args)); } - })); - const output = { - generations, - missingPromptIndices, - startedRunManagers: runManagers - }; - Object.defineProperty(output, RUN_KEY, { - value: runManagers ? { runIds: runManagers?.map((manager) => manager.runId) } : void 0, - configurable: true - }); - return output; - } - /** - * Run the LLM on the given prompts and input, handling caching. - */ - async generate(prompts, options, callbacks) { - if (!Array.isArray(prompts)) throw new Error("Argument 'prompts' is expected to be a string[]"); - let parsedOptions; - if (Array.isArray(options)) parsedOptions = { stop: options }; - else parsedOptions = options; - const [runnableConfig, callOptions] = this._separateRunnableConfigFromCallOptionsCompat(parsedOptions); - runnableConfig.callbacks = runnableConfig.callbacks ?? callbacks; - if (!this.cache) return this._generateUncached(prompts, callOptions, runnableConfig); - const { cache } = this; - const llmStringKey = this._getSerializedCacheKeyParametersForCall(callOptions); - const { generations, missingPromptIndices, startedRunManagers } = await this._generateCached({ - prompts, - cache, - llmStringKey, - parsedOptions: callOptions, - handledOptions: runnableConfig, - runId: runnableConfig.runId - }); - let llmOutput = {}; - if (missingPromptIndices.length > 0) { - const results = await this._generateUncached(missingPromptIndices.map((i) => prompts[i]), callOptions, runnableConfig, startedRunManagers !== void 0 ? missingPromptIndices.map((i) => startedRunManagers?.[i]) : void 0); - await Promise.all(results.generations.map(async (generation, index) => { - const promptIndex = missingPromptIndices[index]; - generations[promptIndex] = generation; - return cache.update(prompts[promptIndex], llmStringKey, generation); - })); - llmOutput = results.llmOutput ?? {}; - } - return { - generations, - llmOutput - }; - } - /** - * Get the identifying parameters of the LLM. - */ - _identifyingParams() { - return {}; + else toolInput = input; + return toolInput; + }).withConfig({ runName: `${fields.name}:parse_input` }), fields.bound]).withConfig({ runName: fields.name }); + super({ + bound: sequence, + config: fields.config ?? {} + }); + this.name = fields.name; + this.description = fields.description; + this.schema = fields.schema; } - _modelType() { - return "base_llm"; + static lc_name() { + return "RunnableToolLike"; } }; /** -* LLM class that provides a simpler interface to subclass than {@link BaseLLM}. +* Given a runnable and a Zod schema, convert the runnable to a tool. * -* Requires only implementing a simpler {@link _call} method instead of {@link _generate}. +* @template RunInput The input type for the runnable. +* @template RunOutput The output type for the runnable. * -* @augments BaseLLM +* @param {Runnable} runnable The runnable to convert to a tool. +* @param fields +* @param {string | undefined} [fields.name] The name of the tool. If not provided, it will default to the name of the runnable. +* @param {string | undefined} [fields.description] The description of the tool. Falls back to the description on the Zod schema if not provided, or undefined if neither are provided. +* @param {InteropZodType} [fields.schema] The Zod schema for the input of the tool. Infers the Zod type from the input type of the runnable. +* @returns {RunnableToolLike, RunOutput>} An instance of `RunnableToolLike` which is a runnable that can be used as a tool. */ -var LLM = class extends BaseLLM { - async _generate(prompts, options, runManager) { - const generations = await Promise.all(prompts.map((prompt, promptIndex) => this._call(prompt, { - ...options, - promptIndex - }, runManager).then((text) => [{ text }]))); - return { generations }; - } -}; +function convertRunnableToTool(runnable, fields) { + const name = fields.name ?? runnable.getName(); + const description = fields.description ?? getSchemaDescription(fields.schema); + if (isSimpleStringZodSchema(fields.schema)) return new RunnableToolLike({ + name, + description, + schema: objectType({ input: stringType() }).transform((input) => input.input), + bound: runnable + }); + return new RunnableToolLike({ + name, + description, + schema: fields.schema, + bound: runnable + }); +} //#endregion -//# sourceMappingURL=llms.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/profile.js -//#region src/language_models/profile.ts -var profile_exports = {}; +//# sourceMappingURL=base.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/transformers.js -//#endregion -//# sourceMappingURL=profile.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/retrievers/document_compressors/index.js -//#region src/retrievers/document_compressors/index.ts -var document_compressors_exports = {}; -__export(document_compressors_exports, { BaseDocumentCompressor: () => BaseDocumentCompressor }); -/** -* Base Document Compression class. All compressors should extend this class. -*/ -var BaseDocumentCompressor = class { - static isBaseDocumentCompressor(x) { - return x?.compressDocuments !== void 0; - } -}; -//#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/base.js -//#region src/prompts/base.ts -/** -* Base class for prompt templates. Exposes a format method that returns a -* string prompt given a set of input values. -*/ -var BasePromptTemplate = class extends Runnable { - lc_serializable = true; - lc_namespace = [ - "langchain_core", - "prompts", - this._getPromptType() - ]; - get lc_attributes() { - return { partialVariables: void 0 }; + + + +//#region src/messages/transformers.ts +const _isMessageType = (msg, types) => { + const typesAsStrings = [...new Set(types?.map((t) => { + if (typeof t === "string") return t; + const instantiatedMsgClass = new t({}); + if (!("getType" in instantiatedMsgClass) || typeof instantiatedMsgClass.getType !== "function") throw new Error("Invalid type provided."); + return instantiatedMsgClass.getType(); + }))]; + const msgType = msg.getType(); + return typesAsStrings.some((t) => t === msgType); +}; +function filterMessages(messagesOrOptions, options) { + if (Array.isArray(messagesOrOptions)) return _filterMessages(messagesOrOptions, options); + return RunnableLambda.from((input) => { + return _filterMessages(input, messagesOrOptions); + }); +} +function _filterMessages(messages, options = {}) { + const { includeNames, excludeNames, includeTypes, excludeTypes, includeIds, excludeIds } = options; + const filtered = []; + for (const msg of messages) { + if (excludeNames && msg.name && excludeNames.includes(msg.name)) continue; + else if (excludeTypes && _isMessageType(msg, excludeTypes)) continue; + else if (excludeIds && msg.id && excludeIds.includes(msg.id)) continue; + if (!(includeTypes || includeIds || includeNames)) filtered.push(msg); + else if (includeNames && msg.name && includeNames.some((iName) => iName === msg.name)) filtered.push(msg); + else if (includeTypes && _isMessageType(msg, includeTypes)) filtered.push(msg); + else if (includeIds && msg.id && includeIds.some((id) => id === msg.id)) filtered.push(msg); } - inputVariables; - outputParser; - partialVariables; - /** - * Metadata to be used for tracing. - */ - metadata; - /** Tags to be used for tracing. */ - tags; - constructor(input) { - super(input); - const { inputVariables } = input; - if (inputVariables.includes("stop")) throw new Error("Cannot have an input variable named 'stop', as it is used internally, please rename."); - Object.assign(this, input); + return filtered; +} +function mergeMessageRuns(messages) { + if (Array.isArray(messages)) return _mergeMessageRuns(messages); + return RunnableLambda.from(_mergeMessageRuns); +} +function _mergeMessageRuns(messages) { + if (!messages.length) return []; + const merged = []; + for (const msg of messages) { + const curr = msg; + const last = merged.pop(); + if (!last) merged.push(curr); + else if (curr.getType() === "tool" || !(curr.getType() === last.getType())) merged.push(last, curr); + else { + const lastChunk = convertToChunk(last); + const currChunk = convertToChunk(curr); + const mergedChunks = lastChunk.concat(currChunk); + if (typeof lastChunk.content === "string" && typeof currChunk.content === "string") mergedChunks.content = `${lastChunk.content}\n${currChunk.content}`; + merged.push(_chunkToMsg(mergedChunks)); + } } - /** - * Merges partial variables and user variables. - * @param userVariables The user variables to merge with the partial variables. - * @returns A Promise that resolves to an object containing the merged variables. - */ - async mergePartialAndUserVariables(userVariables) { - const partialVariables = this.partialVariables ?? {}; - const partialValues = {}; - for (const [key, value] of Object.entries(partialVariables)) if (typeof value === "string") partialValues[key] = value; - else partialValues[key] = await value(); - const allKwargs = { - ...partialValues, - ...userVariables - }; - return allKwargs; + return merged; +} +function trimMessages(messagesOrOptions, options) { + if (Array.isArray(messagesOrOptions)) { + const messages = messagesOrOptions; + if (!options) throw new Error("Options parameter is required when providing messages."); + return _trimMessagesHelper(messages, options); + } else { + const trimmerOptions = messagesOrOptions; + return RunnableLambda.from((input) => _trimMessagesHelper(input, trimmerOptions)).withConfig({ runName: "trim_messages" }); } - /** - * Invokes the prompt template with the given input and options. - * @param input The input to invoke the prompt template with. - * @param options Optional configuration for the callback. - * @returns A Promise that resolves to the output of the prompt template. - */ - async invoke(input, options) { - const metadata = { - ...this.metadata, - ...options?.metadata - }; - const tags = [...this.tags ?? [], ...options?.tags ?? []]; - return this._callWithConfig((input$1) => this.formatPromptValue(input$1), input, { - ...options, - tags, - metadata, - runType: "prompt" - }); +} +async function _trimMessagesHelper(messages, options) { + const { maxTokens, tokenCounter, strategy = "last", allowPartial = false, endOn, startOn, includeSystem = false, textSplitter } = options; + if (startOn && strategy === "first") throw new Error("`startOn` should only be specified if `strategy` is 'last'."); + if (includeSystem && strategy === "first") throw new Error("`includeSystem` should only be specified if `strategy` is 'last'."); + let listTokenCounter; + if ("getNumTokens" in tokenCounter) listTokenCounter = async (msgs) => { + const tokenCounts = await Promise.all(msgs.map((msg) => tokenCounter.getNumTokens(msg.content))); + return tokenCounts.reduce((sum, count) => sum + count, 0); + }; + else listTokenCounter = async (msgs) => tokenCounter(msgs); + let textSplitterFunc = defaultTextSplitter; + if (textSplitter) if ("splitText" in textSplitter) textSplitterFunc = textSplitter.splitText; + else textSplitterFunc = async (text) => textSplitter(text); + if (strategy === "first") return _firstMaxTokens(messages, { + maxTokens, + tokenCounter: listTokenCounter, + textSplitter: textSplitterFunc, + partialStrategy: allowPartial ? "first" : void 0, + endOn + }); + else if (strategy === "last") return _lastMaxTokens(messages, { + maxTokens, + tokenCounter: listTokenCounter, + textSplitter: textSplitterFunc, + allowPartial, + includeSystem, + startOn, + endOn + }); + else throw new Error(`Unrecognized strategy: '${strategy}'. Must be one of 'first' or 'last'.`); +} +async function _firstMaxTokens(messages, options) { + const { maxTokens, tokenCounter, textSplitter, partialStrategy, endOn } = options; + let messagesCopy = [...messages]; + let idx = 0; + for (let i = 0; i < messagesCopy.length; i += 1) { + const remainingMessages = i > 0 ? messagesCopy.slice(0, -i) : messagesCopy; + if (await tokenCounter(remainingMessages) <= maxTokens) { + idx = messagesCopy.length - i; + break; + } } -}; - -//#endregion - -//# sourceMappingURL=base.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/string.js - - - -//#region src/prompts/string.ts -/** -* Base class for string prompt templates. It extends the -* BasePromptTemplate class and overrides the formatPromptValue method to -* return a StringPromptValue. -*/ -var BaseStringPromptTemplate = class extends BasePromptTemplate { - /** - * Formats the prompt given the input values and returns a formatted - * prompt value. - * @param values The input values to format the prompt. - * @returns A Promise that resolves to a formatted prompt value. - */ - async formatPromptValue(values) { - const formattedPrompt = await this.format(values); - return new StringPromptValue(formattedPrompt); + if (idx < messagesCopy.length && partialStrategy) { + let includedPartial = false; + if (Array.isArray(messagesCopy[idx].content)) { + const excluded = messagesCopy[idx]; + if (typeof excluded.content === "string") throw new Error("Expected content to be an array."); + const numBlock = excluded.content.length; + const reversedContent = partialStrategy === "last" ? [...excluded.content].reverse() : excluded.content; + for (let i = 1; i <= numBlock; i += 1) { + const partialContent = partialStrategy === "first" ? reversedContent.slice(0, i) : reversedContent.slice(-i); + const fields = Object.fromEntries(Object.entries(excluded).filter(([k]) => k !== "type" && !k.startsWith("lc_"))); + const updatedMessage = _switchTypeToMessage(excluded.getType(), { + ...fields, + content: partialContent + }); + const slicedMessages = [...messagesCopy.slice(0, idx), updatedMessage]; + if (await tokenCounter(slicedMessages) <= maxTokens) { + messagesCopy = slicedMessages; + idx += 1; + includedPartial = true; + } else break; + } + if (includedPartial && partialStrategy === "last") excluded.content = [...reversedContent].reverse(); + } + if (!includedPartial) { + const excluded = messagesCopy[idx]; + let text; + if (Array.isArray(excluded.content) && excluded.content.some((block) => typeof block === "string" || block.type === "text")) { + const textBlock = excluded.content.find((block) => block.type === "text" && block.text); + text = textBlock?.text; + } else if (typeof excluded.content === "string") text = excluded.content; + if (text) { + const splitTexts = await textSplitter(text); + const numSplits = splitTexts.length; + if (partialStrategy === "last") splitTexts.reverse(); + for (let _ = 0; _ < numSplits - 1; _ += 1) { + splitTexts.pop(); + excluded.content = splitTexts.join(""); + if (await tokenCounter([...messagesCopy.slice(0, idx), excluded]) <= maxTokens) { + if (partialStrategy === "last") excluded.content = [...splitTexts].reverse().join(""); + messagesCopy = [...messagesCopy.slice(0, idx), excluded]; + idx += 1; + break; + } + } + } + } } -}; - -//#endregion - -//# sourceMappingURL=string.js.map -;// CONCATENATED MODULE: ./node_modules/mustache/mustache.mjs -/*! - * mustache.js - Logic-less {{mustache}} templates with JavaScript - * http://github.com/janl/mustache.js - */ - -var mustache_objectToString = Object.prototype.toString; -var mustache_isArray = Array.isArray || function isArrayPolyfill (object) { - return mustache_objectToString.call(object) === '[object Array]'; -}; - -function isFunction (object) { - return typeof object === 'function'; + if (endOn) { + const endOnArr = Array.isArray(endOn) ? endOn : [endOn]; + while (idx > 0 && !_isMessageType(messagesCopy[idx - 1], endOnArr)) idx -= 1; + } + return messagesCopy.slice(0, idx); } - -/** - * More correct typeof string handling array - * which normally returns typeof 'object' - */ -function typeStr (obj) { - return mustache_isArray(obj) ? 'array' : typeof obj; +async function _lastMaxTokens(messages, options) { + const { allowPartial = false, includeSystem = false, endOn, startOn,...rest } = options; + let messagesCopy = messages.map((message) => { + const fields = Object.fromEntries(Object.entries(message).filter(([k]) => k !== "type" && !k.startsWith("lc_"))); + return _switchTypeToMessage(message.getType(), fields, isBaseMessageChunk(message)); + }); + if (endOn) { + const endOnArr = Array.isArray(endOn) ? endOn : [endOn]; + while (messagesCopy.length > 0 && !_isMessageType(messagesCopy[messagesCopy.length - 1], endOnArr)) messagesCopy = messagesCopy.slice(0, -1); + } + const swappedSystem = includeSystem && messagesCopy[0]?.getType() === "system"; + let reversed_ = swappedSystem ? messagesCopy.slice(0, 1).concat(messagesCopy.slice(1).reverse()) : messagesCopy.reverse(); + reversed_ = await _firstMaxTokens(reversed_, { + ...rest, + partialStrategy: allowPartial ? "last" : void 0, + endOn: startOn + }); + if (swappedSystem) return [reversed_[0], ...reversed_.slice(1).reverse()]; + else return reversed_.reverse(); } - -function escapeRegExp (string) { - return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); +const _MSG_CHUNK_MAP = { + human: { + message: HumanMessage, + messageChunk: HumanMessageChunk + }, + ai: { + message: AIMessage, + messageChunk: AIMessageChunk + }, + system: { + message: SystemMessage, + messageChunk: SystemMessageChunk + }, + developer: { + message: SystemMessage, + messageChunk: SystemMessageChunk + }, + tool: { + message: ToolMessage, + messageChunk: ToolMessageChunk + }, + function: { + message: FunctionMessage, + messageChunk: FunctionMessageChunk + }, + generic: { + message: ChatMessage, + messageChunk: ChatMessageChunk + }, + remove: { + message: RemoveMessage, + messageChunk: RemoveMessage + } +}; +function _switchTypeToMessage(messageType, fields, returnChunk) { + let chunk; + let msg; + switch (messageType) { + case "human": + if (returnChunk) chunk = new HumanMessageChunk(fields); + else msg = new HumanMessage(fields); + break; + case "ai": + if (returnChunk) { + let aiChunkFields = { ...fields }; + if ("tool_calls" in aiChunkFields) aiChunkFields = { + ...aiChunkFields, + tool_call_chunks: aiChunkFields.tool_calls?.map((tc) => ({ + ...tc, + type: "tool_call_chunk", + index: void 0, + args: JSON.stringify(tc.args) + })) + }; + chunk = new AIMessageChunk(aiChunkFields); + } else msg = new AIMessage(fields); + break; + case "system": + if (returnChunk) chunk = new SystemMessageChunk(fields); + else msg = new SystemMessage(fields); + break; + case "developer": + if (returnChunk) chunk = new SystemMessageChunk({ + ...fields, + additional_kwargs: { + ...fields.additional_kwargs, + __openai_role__: "developer" + } + }); + else msg = new SystemMessage({ + ...fields, + additional_kwargs: { + ...fields.additional_kwargs, + __openai_role__: "developer" + } + }); + break; + case "tool": + if ("tool_call_id" in fields) if (returnChunk) chunk = new ToolMessageChunk(fields); + else msg = new ToolMessage(fields); + else throw new Error("Can not convert ToolMessage to ToolMessageChunk if 'tool_call_id' field is not defined."); + break; + case "function": + if (returnChunk) chunk = new FunctionMessageChunk(fields); + else { + if (!fields.name) throw new Error("FunctionMessage must have a 'name' field"); + msg = new FunctionMessage(fields); + } + break; + case "generic": + if ("role" in fields) if (returnChunk) chunk = new ChatMessageChunk(fields); + else msg = new ChatMessage(fields); + else throw new Error("Can not convert ChatMessage to ChatMessageChunk if 'role' field is not defined."); + break; + default: throw new Error(`Unrecognized message type ${messageType}`); + } + if (returnChunk && chunk) return chunk; + if (msg) return msg; + throw new Error(`Unrecognized message type ${messageType}`); } - -/** - * Null safe way of checking whether or not an object, - * including its prototype, has a given property - */ -function hasProperty (obj, propName) { - return obj != null && typeof obj === 'object' && (propName in obj); +function _chunkToMsg(chunk) { + const chunkType = chunk.getType(); + let msg; + const fields = Object.fromEntries(Object.entries(chunk).filter(([k]) => !["type", "tool_call_chunks"].includes(k) && !k.startsWith("lc_"))); + if (chunkType in _MSG_CHUNK_MAP) msg = _switchTypeToMessage(chunkType, fields); + if (!msg) throw new Error(`Unrecognized message chunk class ${chunkType}. Supported classes are ${Object.keys(_MSG_CHUNK_MAP)}`); + return msg; } - /** - * Safe way of detecting whether or not the given thing is a primitive and - * whether it has the given property - */ -function primitiveHasOwnProperty (primitive, propName) { - return ( - primitive != null - && typeof primitive !== 'object' - && primitive.hasOwnProperty - && primitive.hasOwnProperty(propName) - ); +* The default text splitter function that splits text by newlines. +* +* @param {string} text +* @returns A promise that resolves to an array of strings split by newlines. +*/ +function defaultTextSplitter(text) { + const splits = text.split("\n"); + return Promise.resolve([...splits.slice(0, -1).map((s) => `${s}\n`), splits[splits.length - 1]]); } -// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 -// See https://github.com/janl/mustache.js/issues/189 -var regExpTest = RegExp.prototype.test; -function testRegExp (re, string) { - return regExpTest.call(re, string); -} +//#endregion -var nonSpaceRe = /\S/; -function isWhitespace (string) { - return !testRegExp(nonSpaceRe, string); -} +//# sourceMappingURL=transformers.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/content/tools.js +//#region src/messages/content/tools.ts +const KNOWN_BLOCK_TYPES = [ + "tool_call", + "tool_call_chunk", + "invalid_tool_call", + "server_tool_call", + "server_tool_call_chunk", + "server_tool_call_result" +]; -var entityMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '/': '/', - '`': '`', - '=': '=' -}; +//#endregion -function escapeHtml (string) { - return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) { - return entityMap[s]; - }); -} +//# sourceMappingURL=tools.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/content/multimodal.js +//#region src/messages/content/multimodal.ts +const multimodal_KNOWN_BLOCK_TYPES = [ + "image", + "video", + "audio", + "text-plain", + "file" +]; -var whiteRe = /\s*/; -var spaceRe = /\s+/; -var equalsRe = /\s*=/; -var curlyRe = /\s*\}/; -var tagRe = /#|\^|\/|>|\{|&|=|!/; +//#endregion -/** - * Breaks up the given `template` string into a tree of tokens. If the `tags` - * argument is given here it must be an array with two string values: the - * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of - * course, the default is to use mustaches (i.e. mustache.tags). - * - * A token is an array with at least 4 elements. The first element is the - * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag - * did not contain a symbol (i.e. {{myValue}}) this element is "name". For - * all text that appears outside a symbol this element is "text". - * - * The second element of a token is its "value". For mustache tags this is - * whatever else was inside the tag besides the opening symbol. For text tokens - * this is the text itself. - * - * The third and fourth elements of the token are the start and end indices, - * respectively, of the token in the original template. - * - * Tokens that are the root node of a subtree contain two more elements: 1) an - * array of tokens in the subtree and 2) the index in the original template at - * which the closing tag for that section begins. - * - * Tokens for partials also contain two more elements: 1) a string value of - * indendation prior to that tag and 2) the index of that tag on that line - - * eg a value of 2 indicates the partial is the third tag on this line. - */ -function parseTemplate (template, tags) { - if (!template) - return []; - var lineHasNonSpace = false; - var sections = []; // Stack to hold section tokens - var tokens = []; // Buffer to hold the tokens - var spaces = []; // Indices of whitespace tokens on the current line - var hasTag = false; // Is there a {{tag}} on the current line? - var nonSpace = false; // Is there a non-space char on the current line? - var indentation = ''; // Tracks indentation for tags that use it - var tagIndex = 0; // Stores a count of number of tags encountered on a line +//# sourceMappingURL=multimodal.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/content/index.js - // Strips all whitespace tokens array for the current line - // if there was a {{#tag}} on it and otherwise only space. - function stripSpace () { - if (hasTag && !nonSpace) { - while (spaces.length) - delete tokens[spaces.pop()]; - } else { - spaces = []; - } - hasTag = false; - nonSpace = false; - } - var openingTagRe, closingTagRe, closingCurlyRe; - function compileTags (tagsToCompile) { - if (typeof tagsToCompile === 'string') - tagsToCompile = tagsToCompile.split(spaceRe, 2); +//#region src/messages/content/index.ts +const KNOWN_BLOCK_TYPES$2 = [ + "text", + "reasoning", + ...KNOWN_BLOCK_TYPES, + ...multimodal_KNOWN_BLOCK_TYPES +]; - if (!mustache_isArray(tagsToCompile) || tagsToCompile.length !== 2) - throw new Error('Invalid tags: ' + tagsToCompile); +//#endregion - openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*'); - closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1])); - closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1])); - } +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/messages/index.js - compileTags(tags || mustache.tags); - var scanner = new Scanner(template); - var start, type, value, chr, token, openSection; - while (!scanner.eos()) { - start = scanner.pos; - // Match any text between tags. - value = scanner.scanUntil(openingTagRe); - if (value) { - for (var i = 0, valueLength = value.length; i < valueLength; ++i) { - chr = value.charAt(i); - if (isWhitespace(chr)) { - spaces.push(tokens.length); - indentation += chr; - } else { - nonSpace = true; - lineHasNonSpace = true; - indentation += ' '; - } - tokens.push([ 'text', chr, start, start + 1 ]); - start += 1; - // Check for whitespace on the current line. - if (chr === '\n') { - stripSpace(); - indentation = ''; - tagIndex = 0; - lineHasNonSpace = false; - } - } - } - // Match the opening tag. - if (!scanner.scan(openingTagRe)) - break; - hasTag = true; - // Get the tag type. - type = scanner.scan(tagRe) || 'name'; - scanner.scan(whiteRe); - // Get the tag value. - if (type === '=') { - value = scanner.scanUntil(equalsRe); - scanner.scan(equalsRe); - scanner.scanUntil(closingTagRe); - } else if (type === '{') { - value = scanner.scanUntil(closingCurlyRe); - scanner.scan(curlyRe); - scanner.scanUntil(closingTagRe); - type = '&'; - } else { - value = scanner.scanUntil(closingTagRe); - } - // Match the closing tag. - if (!scanner.scan(closingTagRe)) - throw new Error('Unclosed tag at ' + scanner.pos); - if (type == '>') { - token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ]; - } else { - token = [ type, value, start, scanner.pos ]; - } - tagIndex++; - tokens.push(token); - if (type === '#' || type === '^') { - sections.push(token); - } else if (type === '/') { - // Check section nesting. - openSection = sections.pop(); - if (!openSection) - throw new Error('Unopened section "' + value + '" at ' + start); +//#region src/messages/index.ts +var messages_exports = {}; +__export(messages_exports, { + AIMessage: () => AIMessage, + AIMessageChunk: () => AIMessageChunk, + BaseMessage: () => BaseMessage, + BaseMessageChunk: () => BaseMessageChunk, + ChatMessage: () => ChatMessage, + ChatMessageChunk: () => ChatMessageChunk, + FunctionMessage: () => FunctionMessage, + FunctionMessageChunk: () => FunctionMessageChunk, + HumanMessage: () => HumanMessage, + HumanMessageChunk: () => HumanMessageChunk, + KNOWN_BLOCK_TYPES: () => KNOWN_BLOCK_TYPES$2, + RemoveMessage: () => RemoveMessage, + SystemMessage: () => SystemMessage, + SystemMessageChunk: () => SystemMessageChunk, + ToolMessage: () => ToolMessage, + ToolMessageChunk: () => ToolMessageChunk, + _isMessageFieldWithRole: () => _isMessageFieldWithRole, + _mergeDicts: () => _mergeDicts, + _mergeLists: () => _mergeLists, + _mergeObj: () => _mergeObj, + _mergeStatus: () => _mergeStatus, + coerceMessageLikeToMessage: () => utils_coerceMessageLikeToMessage, + collapseToolCallChunks: () => collapseToolCallChunks, + convertToChunk: () => convertToChunk, + convertToOpenAIImageBlock: () => convertToOpenAIImageBlock, + convertToProviderContentBlock: () => convertToProviderContentBlock, + defaultTextSplitter: () => defaultTextSplitter, + defaultToolCallParser: () => defaultToolCallParser, + filterMessages: () => filterMessages, + getBufferString: () => getBufferString, + iife: () => utils_iife, + isAIMessage: () => isAIMessage, + isAIMessageChunk: () => isAIMessageChunk, + isBase64ContentBlock: () => isBase64ContentBlock, + isBaseMessage: () => isBaseMessage, + isBaseMessageChunk: () => isBaseMessageChunk, + isChatMessage: () => isChatMessage, + isChatMessageChunk: () => isChatMessageChunk, + isDataContentBlock: () => isDataContentBlock, + isDirectToolOutput: () => isDirectToolOutput, + isFunctionMessage: () => isFunctionMessage, + isFunctionMessageChunk: () => isFunctionMessageChunk, + isHumanMessage: () => isHumanMessage, + isHumanMessageChunk: () => isHumanMessageChunk, + isIDContentBlock: () => isIDContentBlock, + isMessage: () => isMessage, + isOpenAIToolCallArray: () => isOpenAIToolCallArray, + isPlainTextContentBlock: () => isPlainTextContentBlock, + isSystemMessage: () => isSystemMessage, + isSystemMessageChunk: () => isSystemMessageChunk, + isToolMessage: () => isToolMessage, + isToolMessageChunk: () => isToolMessageChunk, + isURLContentBlock: () => isURLContentBlock, + mapChatMessagesToStoredMessages: () => mapChatMessagesToStoredMessages, + mapStoredMessageToChatMessage: () => mapStoredMessageToChatMessage, + mapStoredMessagesToChatMessages: () => mapStoredMessagesToChatMessages, + mergeContent: () => mergeContent, + mergeMessageRuns: () => mergeMessageRuns, + mergeResponseMetadata: () => mergeResponseMetadata, + mergeUsageMetadata: () => mergeUsageMetadata, + parseBase64DataUrl: () => parseBase64DataUrl, + parseMimeType: () => parseMimeType, + trimMessages: () => trimMessages +}); + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/chat_history.js - if (openSection[1] !== value) - throw new Error('Unclosed section "' + openSection[1] + '" at ' + start); - } else if (type === 'name' || type === '{' || type === '&') { - nonSpace = true; - } else if (type === '=') { - // Set the tags for the next time around. - compileTags(value); - } - } - stripSpace(); - // Make sure there are no open sections when we're done. - openSection = sections.pop(); - if (openSection) - throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos); - return nestTokens(squashTokens(tokens)); -} +//#region src/chat_history.ts +var chat_history_exports = {}; +__export(chat_history_exports, { + BaseChatMessageHistory: () => BaseChatMessageHistory, + BaseListChatMessageHistory: () => BaseListChatMessageHistory, + InMemoryChatMessageHistory: () => InMemoryChatMessageHistory +}); /** - * Combines the values of consecutive text tokens in the given `tokens` array - * to a single token. - */ -function squashTokens (tokens) { - var squashedTokens = []; +* Base class for all chat message histories. All chat message histories +* should extend this class. +*/ +var BaseChatMessageHistory = class extends Serializable { + /** + * Add a list of messages. + * + * Implementations should override this method to handle bulk addition of messages + * in an efficient manner to avoid unnecessary round-trips to the underlying store. + * + * @param messages - A list of BaseMessage objects to store. + */ + async addMessages(messages) { + for (const message of messages) await this.addMessage(message); + } +}; +/** +* Base class for all list chat message histories. All list chat message +* histories should extend this class. +*/ +var BaseListChatMessageHistory = class extends Serializable { + /** + * This is a convenience method for adding a human message string to the store. + * Please note that this is a convenience method. Code should favor the + * bulk addMessages interface instead to save on round-trips to the underlying + * persistence layer. + * This method may be deprecated in a future release. + */ + addUserMessage(message) { + return this.addMessage(new HumanMessage(message)); + } + /** + * This is a convenience method for adding an AI message string to the store. + * Please note that this is a convenience method. Code should favor the bulk + * addMessages interface instead to save on round-trips to the underlying + * persistence layer. + * This method may be deprecated in a future release. + */ + addAIMessage(message) { + return this.addMessage(new AIMessage(message)); + } + /** + * Add a list of messages. + * + * Implementations should override this method to handle bulk addition of messages + * in an efficient manner to avoid unnecessary round-trips to the underlying store. + * + * @param messages - A list of BaseMessage objects to store. + */ + async addMessages(messages) { + for (const message of messages) await this.addMessage(message); + } + /** + * Remove all messages from the store. + */ + clear() { + throw new Error("Not implemented."); + } +}; +/** +* Class for storing chat message history in-memory. It extends the +* BaseListChatMessageHistory class and provides methods to get, add, and +* clear messages. +*/ +var InMemoryChatMessageHistory = class extends BaseListChatMessageHistory { + lc_namespace = [ + "langchain", + "stores", + "message", + "in_memory" + ]; + messages = []; + constructor(messages) { + super(...arguments); + this.messages = messages ?? []; + } + /** + * Method to get all the messages stored in the ChatMessageHistory + * instance. + * @returns Array of stored BaseMessage instances. + */ + async getMessages() { + return this.messages; + } + /** + * Method to add a new message to the ChatMessageHistory instance. + * @param message The BaseMessage instance to add. + * @returns A promise that resolves when the message has been added. + */ + async addMessage(message) { + this.messages.push(message); + } + /** + * Method to clear all the messages from the ChatMessageHistory instance. + * @returns A promise that resolves when all messages have been cleared. + */ + async clear() { + this.messages = []; + } +}; - var token, lastToken; - for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { - token = tokens[i]; +//#endregion - if (token) { - if (token[0] === 'text' && lastToken && lastToken[0] === 'text') { - lastToken[1] += token[1]; - lastToken[3] = token[3]; - } else { - squashedTokens.push(token); - lastToken = token; - } - } - } +//# sourceMappingURL=chat_history.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/embeddings.js - return squashedTokens; -} + +//#region src/embeddings.ts +var embeddings_exports = {}; +__export(embeddings_exports, { Embeddings: () => Embeddings }); /** - * Forms the given array of `tokens` into a nested tree structure where - * tokens that represent a section have two additional items: 1) an array of - * all tokens that appear in that section and 2) the index in the original - * template that represents the end of that section. - */ -function nestTokens (tokens) { - var nestedTokens = []; - var collector = nestedTokens; - var sections = []; +* An abstract class that provides methods for embedding documents and +* queries using LangChain. +*/ +var Embeddings = class { + /** + * The async caller should be used by subclasses to make any async calls, + * which will thus benefit from the concurrency and retry logic. + */ + caller; + constructor(params) { + this.caller = new async_caller_AsyncCaller(params ?? {}); + } +}; - var token, section; - for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { - token = tokens[i]; +//#endregion - switch (token[0]) { - case '#': - case '^': - collector.push(token); - sections.push(token); - collector = token[4] = []; - break; - case '/': - section = sections.pop(); - section[5] = token[2]; - collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens; - break; - default: - collector.push(token); - } - } +//# sourceMappingURL=embeddings.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/index.js +//#region src/index.ts +var src_exports = {}; - return nestedTokens; -} +//#endregion -/** - * A simple string scanner that is used by the template parser to find - * tokens in template strings. - */ -function Scanner (string) { - this.string = string; - this.tail = string; - this.pos = 0; -} +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/memory.js + +//#region src/memory.ts +var memory_exports = {}; +__export(memory_exports, { + BaseMemory: () => BaseMemory, + getInputValue: () => getInputValue, + getOutputValue: () => getOutputValue, + getPromptInputKey: () => getPromptInputKey +}); /** - * Returns `true` if the tail is empty (end of string). - */ -Scanner.prototype.eos = function eos () { - return this.tail === ''; +* Abstract base class for memory in LangChain's Chains. Memory refers to +* the state in Chains. It can be used to store information about past +* executions of a Chain and inject that information into the inputs of +* future executions of the Chain. +*/ +var BaseMemory = class {}; +const getValue = (values, key) => { + if (key !== void 0) return values[key]; + const keys = Object.keys(values); + if (keys.length === 1) return values[keys[0]]; +}; +/** +* This function is used by memory classes to select the input value +* to use for the memory. If there is only one input value, it is used. +* If there are multiple input values, the inputKey must be specified. +*/ +const getInputValue = (inputValues, inputKey) => { + const value = getValue(inputValues, inputKey); + if (!value) { + const keys = Object.keys(inputValues); + throw new Error(`input values have ${keys.length} keys, you must specify an input key or pass only 1 key as input`); + } + return value; +}; +/** +* This function is used by memory classes to select the output value +* to use for the memory. If there is only one output value, it is used. +* If there are multiple output values, the outputKey must be specified. +* If no outputKey is specified, an error is thrown. +*/ +const getOutputValue = (outputValues, outputKey) => { + const value = getValue(outputValues, outputKey); + if (!value && value !== "") { + const keys = Object.keys(outputValues); + throw new Error(`output values have ${keys.length} keys, you must specify an output key or pass only 1 key as output`); + } + return value; }; +/** +* Function used by memory classes to get the key of the prompt input, +* excluding any keys that are memory variables or the "stop" key. If +* there is not exactly one prompt input key, an error is thrown. +*/ +function getPromptInputKey(inputs, memoryVariables) { + const promptInputKeys = Object.keys(inputs).filter((key) => !memoryVariables.includes(key) && key !== "stop"); + if (promptInputKeys.length !== 1) throw new Error(`One input key expected, but got ${promptInputKeys.length}`); + return promptInputKeys[0]; +} + +//#endregion -/** - * Tries to match the given regular expression at the current position. - * Returns the matched text if it can match, the empty string otherwise. - */ -Scanner.prototype.scan = function scan (re) { - var match = this.tail.match(re); +//# sourceMappingURL=memory.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompt_values.js - if (!match || match.index !== 0) - return ''; - var string = match[0]; - this.tail = this.tail.substring(string.length); - this.pos += string.length; - return string; -}; +//#region src/prompt_values.ts +var prompt_values_exports = {}; +__export(prompt_values_exports, { + BasePromptValue: () => BasePromptValue, + ChatPromptValue: () => ChatPromptValue, + ImagePromptValue: () => ImagePromptValue, + StringPromptValue: () => StringPromptValue +}); /** - * Skips all text until the given regular expression can be matched. Returns - * the skipped string, which is the entire tail if no match can be made. - */ -Scanner.prototype.scanUntil = function scanUntil (re) { - var index = this.tail.search(re), match; +* Base PromptValue class. All prompt values should extend this class. +*/ +var BasePromptValue = class extends Serializable {}; +/** +* Represents a prompt value as a string. It extends the BasePromptValue +* class and overrides the toString and toChatMessages methods. +*/ +var StringPromptValue = class extends BasePromptValue { + static lc_name() { + return "StringPromptValue"; + } + lc_namespace = ["langchain_core", "prompt_values"]; + lc_serializable = true; + value; + constructor(value) { + super({ value }); + this.value = value; + } + toString() { + return this.value; + } + toChatMessages() { + return [new HumanMessage(this.value)]; + } +}; +/** +* Class that represents a chat prompt value. It extends the +* BasePromptValue and includes an array of BaseMessage instances. +*/ +var ChatPromptValue = class extends BasePromptValue { + lc_namespace = ["langchain_core", "prompt_values"]; + lc_serializable = true; + static lc_name() { + return "ChatPromptValue"; + } + messages; + constructor(fields) { + if (Array.isArray(fields)) fields = { messages: fields }; + super(fields); + this.messages = fields.messages; + } + toString() { + return getBufferString(this.messages); + } + toChatMessages() { + return this.messages; + } +}; +/** +* Class that represents an image prompt value. It extends the +* BasePromptValue and includes an ImageURL instance. +*/ +var ImagePromptValue = class extends BasePromptValue { + lc_namespace = ["langchain_core", "prompt_values"]; + lc_serializable = true; + static lc_name() { + return "ImagePromptValue"; + } + imageUrl; + /** @ignore */ + value; + constructor(fields) { + if (!("imageUrl" in fields)) fields = { imageUrl: fields }; + super(fields); + this.imageUrl = fields.imageUrl; + } + toString() { + return this.imageUrl.url; + } + toChatMessages() { + return [new HumanMessage({ content: [{ + type: "image_url", + image_url: { + detail: this.imageUrl.detail, + url: this.imageUrl.url + } + }] })]; + } +}; - switch (index) { - case -1: - match = this.tail; - this.tail = ''; - break; - case 0: - match = ''; - break; - default: - match = this.tail.substring(0, index); - this.tail = this.tail.substring(index); - } +//#endregion - this.pos += match.length; +//# sourceMappingURL=prompt_values.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/stores.js - return match; -}; -/** - * Represents a rendering context by wrapping a view object and - * maintaining a reference to the parent context. - */ -function Context (view, parentContext) { - this.view = view; - this.cache = { '.': this.view }; - this.parent = parentContext; -} +//#region src/stores.ts +var stores_exports = {}; +__export(stores_exports, { + BaseStore: () => BaseStore, + InMemoryStore: () => InMemoryStore +}); /** - * Creates a new context using the given view with this context - * as the parent. - */ -Context.prototype.push = function push (view) { - return new Context(view, this); -}; - +* Abstract interface for a key-value store. +*/ +var BaseStore = class extends Serializable {}; /** - * Returns the value of the given name in this context, traversing - * up the context hierarchy if the value is absent in this context's view. - */ -Context.prototype.lookup = function lookup (name) { - var cache = this.cache; +* In-memory implementation of the BaseStore using a dictionary. Used for +* storing key-value pairs in memory. +* @example +* ```typescript +* const store = new InMemoryStore(); +* await store.mset( +* Array.from({ length: 5 }).map((_, index) => [ +* `message:id:${index}`, +* index % 2 === 0 +* ? new AIMessage("ai stuff...") +* : new HumanMessage("human stuff..."), +* ]), +* ); +* +* const retrievedMessages = await store.mget(["message:id:0", "message:id:1"]); +* await store.mdelete(await store.yieldKeys("message:id:").toArray()); +* ``` +*/ +var InMemoryStore = class extends BaseStore { + lc_namespace = ["langchain", "storage"]; + store = {}; + /** + * Retrieves the values associated with the given keys from the store. + * @param keys Keys to retrieve values for. + * @returns Array of values associated with the given keys. + */ + async mget(keys) { + return keys.map((key) => this.store[key]); + } + /** + * Sets the values for the given keys in the store. + * @param keyValuePairs Array of key-value pairs to set in the store. + * @returns Promise that resolves when all key-value pairs have been set. + */ + async mset(keyValuePairs) { + for (const [key, value] of keyValuePairs) this.store[key] = value; + } + /** + * Deletes the given keys and their associated values from the store. + * @param keys Keys to delete from the store. + * @returns Promise that resolves when all keys have been deleted. + */ + async mdelete(keys) { + for (const key of keys) delete this.store[key]; + } + /** + * Asynchronous generator that yields keys from the store. If a prefix is + * provided, it only yields keys that start with the prefix. + * @param prefix Optional prefix to filter keys. + * @returns AsyncGenerator that yields keys from the store. + */ + async *yieldKeys(prefix) { + const keys = Object.keys(this.store); + for (const key of keys) if (prefix === void 0 || key.startsWith(prefix)) yield key; + } +}; - var value; - if (cache.hasOwnProperty(name)) { - value = cache[name]; - } else { - var context = this, intermediateValue, names, index, lookupHit = false; +//#endregion - while (context) { - if (name.indexOf('.') > 0) { - intermediateValue = context.view; - names = name.split('.'); - index = 0; +//# sourceMappingURL=stores.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/retrievers/index.js - /** - * Using the dot notion path in `name`, we descend through the - * nested objects. - * - * To be certain that the lookup has been successful, we have to - * check if the last object in the path actually has the property - * we are looking for. We store the result in `lookupHit`. - * - * This is specially necessary for when the value has been set to - * `undefined` and we want to avoid looking up parent contexts. - * - * In the case where dot notation is used, we consider the lookup - * to be successful even if the last "object" in the path is - * not actually an object but a primitive (e.g., a string, or an - * integer), because it is sometimes useful to access a property - * of an autoboxed primitive, such as the length of a string. - **/ - while (intermediateValue != null && index < names.length) { - if (index === names.length - 1) - lookupHit = ( - hasProperty(intermediateValue, names[index]) - || primitiveHasOwnProperty(intermediateValue, names[index]) - ); - intermediateValue = intermediateValue[names[index++]]; - } - } else { - intermediateValue = context.view[name]; - /** - * Only checking against `hasProperty`, which always returns `false` if - * `context.view` is not an object. Deliberately omitting the check - * against `primitiveHasOwnProperty` if dot notation is not used. - * - * Consider this example: - * ``` - * Mustache.render("The length of a football field is {{#length}}{{length}}{{/length}}.", {length: "100 yards"}) - * ``` - * - * If we were to check also against `primitiveHasOwnProperty`, as we do - * in the dot notation case, then render call would return: - * - * "The length of a football field is 9." - * - * rather than the expected: - * - * "The length of a football field is 100 yards." - **/ - lookupHit = hasProperty(context.view, name); - } - if (lookupHit) { - value = intermediateValue; - break; - } - context = context.parent; - } +//#region src/retrievers/index.ts +var retrievers_exports = {}; +__export(retrievers_exports, { BaseRetriever: () => BaseRetriever }); +/** +* Abstract base class for a document retrieval system, designed to +* process string queries and return the most relevant documents from a source. +* +* `BaseRetriever` provides common properties and methods for derived retrievers, +* such as callbacks, tagging, and verbose logging. Custom retrieval systems +* should extend this class and implement `_getRelevantDocuments` to define +* the specific retrieval logic. +* +* @template Metadata - The type of metadata associated with each document, +* defaulting to `Record`. +*/ +var BaseRetriever = class extends Runnable { + /** + * Optional callbacks to handle various events in the retrieval process. + */ + callbacks; + /** + * Tags to label or categorize the retrieval operation. + */ + tags; + /** + * Metadata to provide additional context or information about the retrieval + * operation. + */ + metadata; + /** + * If set to `true`, enables verbose logging for the retrieval process. + */ + verbose; + /** + * Constructs a new `BaseRetriever` instance with optional configuration fields. + * + * @param fields - Optional input configuration that can include `callbacks`, + * `tags`, `metadata`, and `verbose` settings for custom retriever behavior. + */ + constructor(fields) { + super(fields); + this.callbacks = fields?.callbacks; + this.tags = fields?.tags ?? []; + this.metadata = fields?.metadata ?? {}; + this.verbose = fields?.verbose ?? false; + } + /** + * TODO: This should be an abstract method, but we'd like to avoid breaking + * changes to people currently using subclassed custom retrievers. + * Change it on next major release. + */ + /** + * Placeholder method for retrieving relevant documents based on a query. + * + * This method is intended to be implemented by subclasses and will be + * converted to an abstract method in the next major release. Currently, it + * throws an error if not implemented, ensuring that custom retrievers define + * the specific retrieval logic. + * + * @param _query - The query string used to search for relevant documents. + * @param _callbacks - (optional) Callback manager for managing callbacks + * during retrieval. + * @returns A promise resolving to an array of `DocumentInterface` instances relevant to the query. + * @throws {Error} Throws an error indicating the method is not implemented. + */ + _getRelevantDocuments(_query, _callbacks) { + throw new Error("Not implemented!"); + } + /** + * Executes a retrieval operation. + * + * @param input - The query string used to search for relevant documents. + * @param options - (optional) Configuration options for the retrieval run, + * which may include callbacks, tags, and metadata. + * @returns A promise that resolves to an array of `DocumentInterface` instances + * representing the most relevant documents to the query. + */ + async invoke(input, options) { + const parsedConfig = ensureConfig(parseCallbackConfigArg(options)); + const callbackManager_ = await CallbackManager.configure(parsedConfig.callbacks, this.callbacks, parsedConfig.tags, this.tags, parsedConfig.metadata, this.metadata, { verbose: this.verbose }); + const runManager = await callbackManager_?.handleRetrieverStart(this.toJSON(), input, parsedConfig.runId, void 0, void 0, void 0, parsedConfig.runName); + try { + const results = await this._getRelevantDocuments(input, runManager); + await runManager?.handleRetrieverEnd(results); + return results; + } catch (error) { + await runManager?.handleRetrieverError(error); + throw error; + } + } +}; - cache[name] = value; - } +//#endregion - if (isFunction(value)) - value = value.call(this.view); +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/vectorstores.js - return value; -}; -/** - * A Writer knows how to take a stream of tokens and render them to a - * string, given a context. It also maintains a cache of templates to - * avoid the need to parse the same template twice. - */ -function Writer () { - this.templateCache = { - _cache: {}, - set: function set (key, value) { - this._cache[key] = value; - }, - get: function get (key) { - return this._cache[key]; - }, - clear: function clear () { - this._cache = {}; - } - }; -} -/** - * Clears all cached templates in this writer. - */ -Writer.prototype.clearCache = function clearCache () { - if (typeof this.templateCache !== 'undefined') { - this.templateCache.clear(); - } -}; +//#region src/vectorstores.ts +var vectorstores_exports = {}; +__export(vectorstores_exports, { + SaveableVectorStore: () => SaveableVectorStore, + VectorStore: () => VectorStore, + VectorStoreRetriever: () => VectorStoreRetriever +}); /** - * Parses and caches the given `template` according to the given `tags` or - * `mustache.tags` if `tags` is omitted, and returns the array of tokens - * that is generated from the parse. - */ -Writer.prototype.parse = function parse (template, tags) { - var cache = this.templateCache; - var cacheKey = template + ':' + (tags || mustache.tags).join(':'); - var isCacheEnabled = typeof cache !== 'undefined'; - var tokens = isCacheEnabled ? cache.get(cacheKey) : undefined; - - if (tokens == undefined) { - tokens = parseTemplate(template, tags); - isCacheEnabled && cache.set(cacheKey, tokens); - } - return tokens; +* Class for retrieving documents from a `VectorStore` based on vector similarity +* or maximal marginal relevance (MMR). +* +* `VectorStoreRetriever` extends `BaseRetriever`, implementing methods for +* adding documents to the underlying vector store and performing document +* retrieval with optional configurations. +* +* @class VectorStoreRetriever +* @extends BaseRetriever +* @implements VectorStoreRetrieverInterface +* @template V - Type of vector store implementing `VectorStoreInterface`. +*/ +var VectorStoreRetriever = class extends BaseRetriever { + static lc_name() { + return "VectorStoreRetriever"; + } + get lc_namespace() { + return ["langchain_core", "vectorstores"]; + } + /** + * The instance of `VectorStore` used for storing and retrieving document embeddings. + * This vector store must implement the `VectorStoreInterface` to be compatible + * with the retriever’s operations. + */ + vectorStore; + /** + * Specifies the number of documents to retrieve for each search query. + * Defaults to 4 if not specified, providing a basic result count for similarity or MMR searches. + */ + k = 4; + /** + * Determines the type of search operation to perform on the vector store. + * + * - `"similarity"` (default): Conducts a similarity search based purely on vector similarity + * to the query. + * - `"mmr"`: Executes a maximal marginal relevance (MMR) search, balancing relevance and + * diversity in the retrieved results. + */ + searchType = "similarity"; + /** + * Additional options specific to maximal marginal relevance (MMR) search, applicable + * only if `searchType` is set to `"mmr"`. + * + * Includes: + * - `fetchK`: The initial number of documents fetched before applying the MMR algorithm, + * allowing for a larger selection from which to choose the most diverse results. + * - `lambda`: A parameter between 0 and 1 to adjust the relevance-diversity balance, + * where 0 prioritizes diversity and 1 prioritizes relevance. + */ + searchKwargs; + /** + * Optional filter applied to search results, defined by the `FilterType` of the vector store. + * Allows for refined, targeted results by restricting the returned documents based + * on specified filter criteria. + */ + filter; + /** + * Returns the type of vector store, as defined by the `vectorStore` instance. + * + * @returns {string} The vector store type. + */ + _vectorstoreType() { + return this.vectorStore._vectorstoreType(); + } + /** + * Initializes a new instance of `VectorStoreRetriever` with the specified configuration. + * + * This constructor configures the retriever to interact with a given `VectorStore` + * and supports different retrieval strategies, including similarity search and maximal + * marginal relevance (MMR) search. Various options allow customization of the number + * of documents retrieved per query, filtering based on conditions, and fine-tuning + * MMR-specific parameters. + * + * @param fields - Configuration options for setting up the retriever: + * + * - `vectorStore` (required): The `VectorStore` instance implementing `VectorStoreInterface` + * that will be used to store and retrieve document embeddings. This is the core component + * of the retriever, enabling vector-based similarity and MMR searches. + * + * - `k` (optional): Specifies the number of documents to retrieve per search query. If not + * provided, defaults to 4. This count determines the number of most relevant documents returned + * for each search operation, balancing performance with comprehensiveness. + * + * - `searchType` (optional): Defines the search approach used by the retriever, allowing for + * flexibility between two methods: + * - `"similarity"` (default): A similarity-based search, retrieving documents with high vector + * similarity to the query. This type prioritizes relevance and is often used when diversity + * among results is less critical. + * - `"mmr"`: Maximal Marginal Relevance search, which combines relevance with diversity. MMR + * is useful for scenarios where varied content is essential, as it selects results that + * both match the query and introduce content diversity. + * + * - `filter` (optional): A filter of type `FilterType`, defined by the vector store, that allows + * for refined and targeted search results. This filter applies specified conditions to limit + * which documents are eligible for retrieval, offering control over the scope of results. + * + * - `searchKwargs` (optional, applicable only if `searchType` is `"mmr"`): Additional settings + * for configuring MMR-specific behavior. These parameters allow further tuning of the MMR + * search process: + * - `fetchK`: The initial number of documents fetched from the vector store before the MMR + * algorithm is applied. Fetching a larger set enables the algorithm to select a more + * diverse subset of documents. + * - `lambda`: A parameter controlling the relevance-diversity balance, where 0 emphasizes + * diversity and 1 prioritizes relevance. Intermediate values provide a blend of the two, + * allowing customization based on the importance of content variety relative to query relevance. + */ + constructor(fields) { + super(fields); + this.vectorStore = fields.vectorStore; + this.k = fields.k ?? this.k; + this.searchType = fields.searchType ?? this.searchType; + this.filter = fields.filter; + if (fields.searchType === "mmr") this.searchKwargs = fields.searchKwargs; + } + /** + * Retrieves relevant documents based on the specified query, using either + * similarity or maximal marginal relevance (MMR) search. + * + * If `searchType` is set to `"mmr"`, performs an MMR search to balance + * similarity and diversity among results. If `searchType` is `"similarity"`, + * retrieves results purely based on similarity to the query. + * + * @param query - The query string used to find relevant documents. + * @param runManager - Optional callback manager for tracking retrieval progress. + * @returns A promise that resolves to an array of `DocumentInterface` instances + * representing the most relevant documents to the query. + * @throws {Error} Throws an error if MMR search is requested but not supported + * by the vector store. + * @protected + */ + async _getRelevantDocuments(query, runManager) { + if (this.searchType === "mmr") { + if (typeof this.vectorStore.maxMarginalRelevanceSearch !== "function") throw new Error(`The vector store backing this retriever, ${this._vectorstoreType()} does not support max marginal relevance search.`); + return this.vectorStore.maxMarginalRelevanceSearch(query, { + k: this.k, + filter: this.filter, + ...this.searchKwargs + }, runManager?.getChild("vectorstore")); + } + return this.vectorStore.similaritySearch(query, this.k, this.filter, runManager?.getChild("vectorstore")); + } + /** + * Adds an array of documents to the vector store, embedding them as part of + * the storage process. + * + * This method delegates document embedding and storage to the `addDocuments` + * method of the underlying vector store. + * + * @param documents - An array of documents to embed and add to the vector store. + * @param options - Optional settings to customize document addition. + * @returns A promise that resolves to an array of document IDs or `void`, + * depending on the vector store's implementation. + */ + async addDocuments(documents, options) { + return this.vectorStore.addDocuments(documents, options); + } }; - /** - * High-level method that is used to render the given `template` with - * the given `view`. - * - * The optional `partials` argument may be an object that contains the - * names and templates of partials that are used in the template. It may - * also be a function that is used to load partial templates on the fly - * that takes a single argument: the name of the partial. - * - * If the optional `config` argument is given here, then it should be an - * object with a `tags` attribute or an `escape` attribute or both. - * If an array is passed, then it will be interpreted the same way as - * a `tags` attribute on a `config` object. - * - * The `tags` attribute of a `config` object must be an array with two - * string values: the opening and closing tags used in the template (e.g. - * [ "<%", "%>" ]). The default is to mustache.tags. - * - * The `escape` attribute of a `config` object must be a function which - * accepts a string as input and outputs a safely escaped string. - * If an `escape` function is not provided, then an HTML-safe string - * escaping function is used as the default. - */ -Writer.prototype.render = function render (template, view, partials, config) { - var tags = this.getConfigTags(config); - var tokens = this.parse(template, tags); - var context = (view instanceof Context) ? view : new Context(view, undefined); - return this.renderTokens(tokens, context, partials, template, config); +* Abstract class representing a vector storage system for performing +* similarity searches on embedded documents. +* +* `VectorStore` provides methods for adding precomputed vectors or documents, +* removing documents based on criteria, and performing similarity searches +* with optional scoring. Subclasses are responsible for implementing specific +* storage mechanisms and the exact behavior of certain abstract methods. +* +* @abstract +* @extends Serializable +* @implements VectorStoreInterface +*/ +var VectorStore = class extends Serializable { + /** + * Namespace within LangChain to uniquely identify this vector store's + * location, based on the vector store type. + * + * @internal + */ + lc_namespace = [ + "langchain", + "vectorstores", + this._vectorstoreType() + ]; + /** + * Embeddings interface for generating vector embeddings from text queries, + * enabling vector-based similarity searches. + */ + embeddings; + /** + * Initializes a new vector store with embeddings and database configuration. + * + * @param embeddings - Instance of `EmbeddingsInterface` used to embed queries. + * @param dbConfig - Configuration settings for the database or storage system. + */ + constructor(embeddings, dbConfig) { + super(dbConfig); + this.embeddings = embeddings; + } + /** + * Deletes documents from the vector store based on the specified parameters. + * + * @param _params - Flexible key-value pairs defining conditions for document deletion. + * @returns A promise that resolves once the deletion is complete. + */ + async delete(_params) { + throw new Error("Not implemented."); + } + /** + * Searches for documents similar to a text query by embedding the query and + * performing a similarity search on the resulting vector. + * + * @param query - Text query for finding similar documents. + * @param k - Number of similar results to return. Defaults to 4. + * @param filter - Optional filter based on `FilterType`. + * @param _callbacks - Optional callbacks for monitoring search progress + * @returns A promise resolving to an array of `DocumentInterface` instances representing similar documents. + */ + async similaritySearch(query, k = 4, filter = void 0, _callbacks = void 0) { + const results = await this.similaritySearchVectorWithScore(await this.embeddings.embedQuery(query), k, filter); + return results.map((result) => result[0]); + } + /** + * Searches for documents similar to a text query by embedding the query, + * and returns results with similarity scores. + * + * @param query - Text query for finding similar documents. + * @param k - Number of similar results to return. Defaults to 4. + * @param filter - Optional filter based on `FilterType`. + * @param _callbacks - Optional callbacks for monitoring search progress + * @returns A promise resolving to an array of tuples, each containing a + * document and its similarity score. + */ + async similaritySearchWithScore(query, k = 4, filter = void 0, _callbacks = void 0) { + return this.similaritySearchVectorWithScore(await this.embeddings.embedQuery(query), k, filter); + } + /** + * Creates a `VectorStore` instance from an array of text strings and optional + * metadata, using the specified embeddings and database configuration. + * + * Subclasses must implement this method to define how text and metadata + * are embedded and stored in the vector store. Throws an error if not overridden. + * + * @param _texts - Array of strings representing the text documents to be stored. + * @param _metadatas - Metadata for the texts, either as an array (one for each text) + * or a single object (applied to all texts). + * @param _embeddings - Instance of `EmbeddingsInterface` to embed the texts. + * @param _dbConfig - Database configuration settings. + * @returns A promise that resolves to a new `VectorStore` instance. + * @throws {Error} Throws an error if this method is not overridden by a subclass. + */ + static fromTexts(_texts, _metadatas, _embeddings, _dbConfig) { + throw new Error("the Langchain vectorstore implementation you are using forgot to override this, please report a bug"); + } + /** + * Creates a `VectorStore` instance from an array of documents, using the specified + * embeddings and database configuration. + * + * Subclasses must implement this method to define how documents are embedded + * and stored. Throws an error if not overridden. + * + * @param _docs - Array of `DocumentInterface` instances representing the documents to be stored. + * @param _embeddings - Instance of `EmbeddingsInterface` to embed the documents. + * @param _dbConfig - Database configuration settings. + * @returns A promise that resolves to a new `VectorStore` instance. + * @throws {Error} Throws an error if this method is not overridden by a subclass. + */ + static fromDocuments(_docs, _embeddings, _dbConfig) { + throw new Error("the Langchain vectorstore implementation you are using forgot to override this, please report a bug"); + } + /** + * Creates a `VectorStoreRetriever` instance with flexible configuration options. + * + * @param kOrFields + * - If a number is provided, it sets the `k` parameter (number of items to retrieve). + * - If an object is provided, it should contain various configuration options. + * @param filter + * - Optional filter criteria to limit the items retrieved based on the specified filter type. + * @param callbacks + * - Optional callbacks that may be triggered at specific stages of the retrieval process. + * @param tags + * - Tags to categorize or label the `VectorStoreRetriever`. Defaults to an empty array if not provided. + * @param metadata + * - Additional metadata as key-value pairs to add contextual information for the retrieval process. + * @param verbose + * - If `true`, enables detailed logging for the retrieval process. Defaults to `false`. + * + * @returns + * - A configured `VectorStoreRetriever` instance based on the provided parameters. + * + * @example + * Basic usage with a `k` value: + * ```typescript + * const retriever = myVectorStore.asRetriever(5); + * ``` + * + * Usage with a configuration object: + * ```typescript + * const retriever = myVectorStore.asRetriever({ + * k: 10, + * filter: myFilter, + * tags: ['example', 'test'], + * verbose: true, + * searchType: 'mmr', + * searchKwargs: { alpha: 0.5 }, + * }); + * ``` + */ + asRetriever(kOrFields, filter, callbacks, tags, metadata, verbose) { + if (typeof kOrFields === "number") return new VectorStoreRetriever({ + vectorStore: this, + k: kOrFields, + filter, + tags: [...tags ?? [], this._vectorstoreType()], + metadata, + verbose, + callbacks + }); + else { + const params = { + vectorStore: this, + k: kOrFields?.k, + filter: kOrFields?.filter, + tags: [...kOrFields?.tags ?? [], this._vectorstoreType()], + metadata: kOrFields?.metadata, + verbose: kOrFields?.verbose, + callbacks: kOrFields?.callbacks, + searchType: kOrFields?.searchType + }; + if (kOrFields?.searchType === "mmr") return new VectorStoreRetriever({ + ...params, + searchKwargs: kOrFields.searchKwargs + }); + return new VectorStoreRetriever({ ...params }); + } + } }; - /** - * Low-level method that renders the given array of `tokens` using - * the given `context` and `partials`. - * - * Note: The `originalTemplate` is only ever used to extract the portion - * of the original template that was contained in a higher-order section. - * If the template doesn't use higher-order sections, this argument may - * be omitted. - */ -Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate, config) { - var buffer = ''; - - var token, symbol, value; - for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { - value = undefined; - token = tokens[i]; - symbol = token[0]; - - if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate, config); - else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate, config); - else if (symbol === '>') value = this.renderPartial(token, context, partials, config); - else if (symbol === '&') value = this.unescapedValue(token, context); - else if (symbol === 'name') value = this.escapedValue(token, context, config); - else if (symbol === 'text') value = this.rawValue(token); - - if (value !== undefined) - buffer += value; - } - - return buffer; -}; - -Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate, config) { - var self = this; - var buffer = ''; - var value = context.lookup(token[1]); - - // This function is used to render an arbitrary template - // in the current context by higher-order sections. - function subRender (template) { - return self.render(template, context, partials, config); - } - - if (!value) return; - - if (mustache_isArray(value)) { - for (var j = 0, valueLength = value.length; j < valueLength; ++j) { - buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate, config); - } - } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') { - buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate, config); - } else if (isFunction(value)) { - if (typeof originalTemplate !== 'string') - throw new Error('Cannot use higher-order sections without the original template'); - - // Extract the portion of the original template that the section contains. - value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender); - - if (value != null) - buffer += value; - } else { - buffer += this.renderTokens(token[4], context, partials, originalTemplate, config); - } - return buffer; +* Abstract class extending `VectorStore` that defines a contract for saving +* and loading vector store instances. +* +* The `SaveableVectorStore` class allows vector store implementations to +* persist their data and retrieve it when needed.The format for saving and +* loading data is left to the implementing subclass. +* +* Subclasses must implement the `save` method to handle their custom +* serialization logic, while the `load` method enables reconstruction of a +* vector store from saved data, requiring compatible embeddings through the +* `EmbeddingsInterface`. +* +* @abstract +* @extends VectorStore +*/ +var SaveableVectorStore = class extends VectorStore { + /** + * Loads a vector store instance from the specified directory, using the + * provided embeddings to ensure compatibility. + * + * This static method reconstructs a `SaveableVectorStore` from previously + * saved data. Implementations should interpret the saved data format to + * recreate the vector store instance. + * + * @param _directory - The directory path from which the vector store + * data will be loaded. + * @param _embeddings - An instance of `EmbeddingsInterface` to align + * the embeddings with the loaded vector data. + * @returns A promise that resolves to a `SaveableVectorStore` instance + * constructed from the saved data. + */ + static load(_directory, _embeddings) { + throw new Error("Not implemented"); + } }; -Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate, config) { - var value = context.lookup(token[1]); - - // Use JavaScript's definition of falsy. Include empty arrays. - // See https://github.com/janl/mustache.js/issues/186 - if (!value || (mustache_isArray(value) && value.length === 0)) - return this.renderTokens(token[4], context, partials, originalTemplate, config); -}; +//#endregion -Writer.prototype.indentPartial = function indentPartial (partial, indentation, lineHasNonSpace) { - var filteredIndentation = indentation.replace(/[^ \t]/g, ''); - var partialByNl = partial.split('\n'); - for (var i = 0; i < partialByNl.length; i++) { - if (partialByNl[i].length && (i > 0 || !lineHasNonSpace)) { - partialByNl[i] = filteredIndentation + partialByNl[i]; - } - } - return partialByNl.join('\n'); -}; +//# sourceMappingURL=vectorstores.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/js-sha256/hash.js -Writer.prototype.renderPartial = function renderPartial (token, context, partials, config) { - if (!partials) return; - var tags = this.getConfigTags(config); - var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; - if (value != null) { - var lineHasNonSpace = token[6]; - var tagIndex = token[5]; - var indentation = token[4]; - var indentedValue = value; - if (tagIndex == 0 && indentation) { - indentedValue = this.indentPartial(value, indentation, lineHasNonSpace); - } - var tokens = this.parse(indentedValue, tags); - return this.renderTokens(tokens, context, partials, indentedValue, config); - } +//#region src/utils/js-sha256/hash.ts +var HEX_CHARS = "0123456789abcdef".split(""); +var EXTRA = [ + -2147483648, + 8388608, + 32768, + 128 +]; +var SHIFT = [ + 24, + 16, + 8, + 0 +]; +var K = [ + 1116352408, + 1899447441, + 3049323471, + 3921009573, + 961987163, + 1508970993, + 2453635748, + 2870763221, + 3624381080, + 310598401, + 607225278, + 1426881987, + 1925078388, + 2162078206, + 2614888103, + 3248222580, + 3835390401, + 4022224774, + 264347078, + 604807628, + 770255983, + 1249150122, + 1555081692, + 1996064986, + 2554220882, + 2821834349, + 2952996808, + 3210313671, + 3336571891, + 3584528711, + 113926993, + 338241895, + 666307205, + 773529912, + 1294757372, + 1396182291, + 1695183700, + 1986661051, + 2177026350, + 2456956037, + 2730485921, + 2820302411, + 3259730800, + 3345764771, + 3516065817, + 3600352804, + 4094571909, + 275423344, + 430227734, + 506948616, + 659060556, + 883997877, + 958139571, + 1322822218, + 1537002063, + 1747873779, + 1955562222, + 2024104815, + 2227730452, + 2361852424, + 2428436474, + 2756734187, + 3204031479, + 3329325298 +]; +var blocks = []; +function Sha256(is224, sharedMemory) { + if (sharedMemory) { + blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + this.blocks = blocks; + } else this.blocks = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ]; + if (is224) { + this.h0 = 3238371032; + this.h1 = 914150663; + this.h2 = 812702999; + this.h3 = 4144912697; + this.h4 = 4290775857; + this.h5 = 1750603025; + this.h6 = 1694076839; + this.h7 = 3204075428; + } else { + this.h0 = 1779033703; + this.h1 = 3144134277; + this.h2 = 1013904242; + this.h3 = 2773480762; + this.h4 = 1359893119; + this.h5 = 2600822924; + this.h6 = 528734635; + this.h7 = 1541459225; + } + this.block = this.start = this.bytes = this.hBytes = 0; + this.finalized = this.hashed = false; + this.first = true; + this.is224 = is224; +} +Sha256.prototype.update = function(message) { + if (this.finalized) return; + var notString, type = typeof message; + if (type !== "string") { + if (type === "object") { + if (message === null) throw new Error(ERROR); + else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) message = new Uint8Array(message); + else if (!Array.isArray(message)) { + if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) throw new Error(ERROR); + } + } else throw new Error(ERROR); + notString = true; + } + var code, index = 0, i, length = message.length, blocks$1 = this.blocks; + while (index < length) { + if (this.hashed) { + this.hashed = false; + blocks$1[0] = this.block; + this.block = blocks$1[16] = blocks$1[1] = blocks$1[2] = blocks$1[3] = blocks$1[4] = blocks$1[5] = blocks$1[6] = blocks$1[7] = blocks$1[8] = blocks$1[9] = blocks$1[10] = blocks$1[11] = blocks$1[12] = blocks$1[13] = blocks$1[14] = blocks$1[15] = 0; + } + if (notString) for (i = this.start; index < length && i < 64; ++index) blocks$1[i >>> 2] |= message[index] << SHIFT[i++ & 3]; + else for (i = this.start; index < length && i < 64; ++index) { + code = message.charCodeAt(index); + if (code < 128) blocks$1[i >>> 2] |= code << SHIFT[i++ & 3]; + else if (code < 2048) { + blocks$1[i >>> 2] |= (192 | code >>> 6) << SHIFT[i++ & 3]; + blocks$1[i >>> 2] |= (128 | code & 63) << SHIFT[i++ & 3]; + } else if (code < 55296 || code >= 57344) { + blocks$1[i >>> 2] |= (224 | code >>> 12) << SHIFT[i++ & 3]; + blocks$1[i >>> 2] |= (128 | code >>> 6 & 63) << SHIFT[i++ & 3]; + blocks$1[i >>> 2] |= (128 | code & 63) << SHIFT[i++ & 3]; + } else { + code = 65536 + ((code & 1023) << 10 | message.charCodeAt(++index) & 1023); + blocks$1[i >>> 2] |= (240 | code >>> 18) << SHIFT[i++ & 3]; + blocks$1[i >>> 2] |= (128 | code >>> 12 & 63) << SHIFT[i++ & 3]; + blocks$1[i >>> 2] |= (128 | code >>> 6 & 63) << SHIFT[i++ & 3]; + blocks$1[i >>> 2] |= (128 | code & 63) << SHIFT[i++ & 3]; + } + } + this.lastByteIndex = i; + this.bytes += i - this.start; + if (i >= 64) { + this.block = blocks$1[16]; + this.start = i - 64; + this.hash(); + this.hashed = true; + } else this.start = i; + } + if (this.bytes > 4294967295) { + this.hBytes += this.bytes / 4294967296 << 0; + this.bytes = this.bytes % 4294967296; + } + return this; }; - -Writer.prototype.unescapedValue = function unescapedValue (token, context) { - var value = context.lookup(token[1]); - if (value != null) - return value; +Sha256.prototype.finalize = function() { + if (this.finalized) return; + this.finalized = true; + var blocks$1 = this.blocks, i = this.lastByteIndex; + blocks$1[16] = this.block; + blocks$1[i >>> 2] |= EXTRA[i & 3]; + this.block = blocks$1[16]; + if (i >= 56) { + if (!this.hashed) this.hash(); + blocks$1[0] = this.block; + blocks$1[16] = blocks$1[1] = blocks$1[2] = blocks$1[3] = blocks$1[4] = blocks$1[5] = blocks$1[6] = blocks$1[7] = blocks$1[8] = blocks$1[9] = blocks$1[10] = blocks$1[11] = blocks$1[12] = blocks$1[13] = blocks$1[14] = blocks$1[15] = 0; + } + blocks$1[14] = this.hBytes << 3 | this.bytes >>> 29; + blocks$1[15] = this.bytes << 3; + this.hash(); }; - -Writer.prototype.escapedValue = function escapedValue (token, context, config) { - var escape = this.getConfigEscape(config) || mustache.escape; - var value = context.lookup(token[1]); - if (value != null) - return (typeof value === 'number' && escape === mustache.escape) ? String(value) : escape(value); +Sha256.prototype.hash = function() { + var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4, f = this.h5, g = this.h6, h = this.h7, blocks$1 = this.blocks, j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc; + for (j = 16; j < 64; ++j) { + t1 = blocks$1[j - 15]; + s0 = (t1 >>> 7 | t1 << 25) ^ (t1 >>> 18 | t1 << 14) ^ t1 >>> 3; + t1 = blocks$1[j - 2]; + s1 = (t1 >>> 17 | t1 << 15) ^ (t1 >>> 19 | t1 << 13) ^ t1 >>> 10; + blocks$1[j] = blocks$1[j - 16] + s0 + blocks$1[j - 7] + s1 << 0; + } + bc = b & c; + for (j = 0; j < 64; j += 4) { + if (this.first) { + if (this.is224) { + ab = 300032; + t1 = blocks$1[0] - 1413257819; + h = t1 - 150054599 << 0; + d = t1 + 24177077 << 0; + } else { + ab = 704751109; + t1 = blocks$1[0] - 210244248; + h = t1 - 1521486534 << 0; + d = t1 + 143694565 << 0; + } + this.first = false; + } else { + s0 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10); + s1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7); + ab = a & b; + maj = ab ^ a & c ^ bc; + ch = e & f ^ ~e & g; + t1 = h + s1 + ch + K[j] + blocks$1[j]; + t2 = s0 + maj; + h = d + t1 << 0; + d = t1 + t2 << 0; + } + s0 = (d >>> 2 | d << 30) ^ (d >>> 13 | d << 19) ^ (d >>> 22 | d << 10); + s1 = (h >>> 6 | h << 26) ^ (h >>> 11 | h << 21) ^ (h >>> 25 | h << 7); + da = d & a; + maj = da ^ d & b ^ ab; + ch = g & h ^ ~g & e; + t1 = f + s1 + ch + K[j + 1] + blocks$1[j + 1]; + t2 = s0 + maj; + g = c + t1 << 0; + c = t1 + t2 << 0; + s0 = (c >>> 2 | c << 30) ^ (c >>> 13 | c << 19) ^ (c >>> 22 | c << 10); + s1 = (g >>> 6 | g << 26) ^ (g >>> 11 | g << 21) ^ (g >>> 25 | g << 7); + cd = c & d; + maj = cd ^ c & a ^ da; + ch = f & g ^ ~f & h; + t1 = e + s1 + ch + K[j + 2] + blocks$1[j + 2]; + t2 = s0 + maj; + f = b + t1 << 0; + b = t1 + t2 << 0; + s0 = (b >>> 2 | b << 30) ^ (b >>> 13 | b << 19) ^ (b >>> 22 | b << 10); + s1 = (f >>> 6 | f << 26) ^ (f >>> 11 | f << 21) ^ (f >>> 25 | f << 7); + bc = b & c; + maj = bc ^ b & d ^ cd; + ch = f & g ^ ~f & h; + t1 = e + s1 + ch + K[j + 3] + blocks$1[j + 3]; + t2 = s0 + maj; + e = a + t1 << 0; + a = t1 + t2 << 0; + this.chromeBugWorkAround = true; + } + this.h0 = this.h0 + a << 0; + this.h1 = this.h1 + b << 0; + this.h2 = this.h2 + c << 0; + this.h3 = this.h3 + d << 0; + this.h4 = this.h4 + e << 0; + this.h5 = this.h5 + f << 0; + this.h6 = this.h6 + g << 0; + this.h7 = this.h7 + h << 0; }; - -Writer.prototype.rawValue = function rawValue (token) { - return token[1]; +Sha256.prototype.hex = function() { + this.finalize(); + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, h6 = this.h6, h7 = this.h7; + var hex = HEX_CHARS[h0 >>> 28 & 15] + HEX_CHARS[h0 >>> 24 & 15] + HEX_CHARS[h0 >>> 20 & 15] + HEX_CHARS[h0 >>> 16 & 15] + HEX_CHARS[h0 >>> 12 & 15] + HEX_CHARS[h0 >>> 8 & 15] + HEX_CHARS[h0 >>> 4 & 15] + HEX_CHARS[h0 & 15] + HEX_CHARS[h1 >>> 28 & 15] + HEX_CHARS[h1 >>> 24 & 15] + HEX_CHARS[h1 >>> 20 & 15] + HEX_CHARS[h1 >>> 16 & 15] + HEX_CHARS[h1 >>> 12 & 15] + HEX_CHARS[h1 >>> 8 & 15] + HEX_CHARS[h1 >>> 4 & 15] + HEX_CHARS[h1 & 15] + HEX_CHARS[h2 >>> 28 & 15] + HEX_CHARS[h2 >>> 24 & 15] + HEX_CHARS[h2 >>> 20 & 15] + HEX_CHARS[h2 >>> 16 & 15] + HEX_CHARS[h2 >>> 12 & 15] + HEX_CHARS[h2 >>> 8 & 15] + HEX_CHARS[h2 >>> 4 & 15] + HEX_CHARS[h2 & 15] + HEX_CHARS[h3 >>> 28 & 15] + HEX_CHARS[h3 >>> 24 & 15] + HEX_CHARS[h3 >>> 20 & 15] + HEX_CHARS[h3 >>> 16 & 15] + HEX_CHARS[h3 >>> 12 & 15] + HEX_CHARS[h3 >>> 8 & 15] + HEX_CHARS[h3 >>> 4 & 15] + HEX_CHARS[h3 & 15] + HEX_CHARS[h4 >>> 28 & 15] + HEX_CHARS[h4 >>> 24 & 15] + HEX_CHARS[h4 >>> 20 & 15] + HEX_CHARS[h4 >>> 16 & 15] + HEX_CHARS[h4 >>> 12 & 15] + HEX_CHARS[h4 >>> 8 & 15] + HEX_CHARS[h4 >>> 4 & 15] + HEX_CHARS[h4 & 15] + HEX_CHARS[h5 >>> 28 & 15] + HEX_CHARS[h5 >>> 24 & 15] + HEX_CHARS[h5 >>> 20 & 15] + HEX_CHARS[h5 >>> 16 & 15] + HEX_CHARS[h5 >>> 12 & 15] + HEX_CHARS[h5 >>> 8 & 15] + HEX_CHARS[h5 >>> 4 & 15] + HEX_CHARS[h5 & 15] + HEX_CHARS[h6 >>> 28 & 15] + HEX_CHARS[h6 >>> 24 & 15] + HEX_CHARS[h6 >>> 20 & 15] + HEX_CHARS[h6 >>> 16 & 15] + HEX_CHARS[h6 >>> 12 & 15] + HEX_CHARS[h6 >>> 8 & 15] + HEX_CHARS[h6 >>> 4 & 15] + HEX_CHARS[h6 & 15]; + if (!this.is224) hex += HEX_CHARS[h7 >>> 28 & 15] + HEX_CHARS[h7 >>> 24 & 15] + HEX_CHARS[h7 >>> 20 & 15] + HEX_CHARS[h7 >>> 16 & 15] + HEX_CHARS[h7 >>> 12 & 15] + HEX_CHARS[h7 >>> 8 & 15] + HEX_CHARS[h7 >>> 4 & 15] + HEX_CHARS[h7 & 15]; + return hex; }; - -Writer.prototype.getConfigTags = function getConfigTags (config) { - if (mustache_isArray(config)) { - return config; - } - else if (config && typeof config === 'object') { - return config.tags; - } - else { - return undefined; - } +Sha256.prototype.toString = Sha256.prototype.hex; +Sha256.prototype.digest = function() { + this.finalize(); + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, h6 = this.h6, h7 = this.h7; + var arr = [ + h0 >>> 24 & 255, + h0 >>> 16 & 255, + h0 >>> 8 & 255, + h0 & 255, + h1 >>> 24 & 255, + h1 >>> 16 & 255, + h1 >>> 8 & 255, + h1 & 255, + h2 >>> 24 & 255, + h2 >>> 16 & 255, + h2 >>> 8 & 255, + h2 & 255, + h3 >>> 24 & 255, + h3 >>> 16 & 255, + h3 >>> 8 & 255, + h3 & 255, + h4 >>> 24 & 255, + h4 >>> 16 & 255, + h4 >>> 8 & 255, + h4 & 255, + h5 >>> 24 & 255, + h5 >>> 16 & 255, + h5 >>> 8 & 255, + h5 & 255, + h6 >>> 24 & 255, + h6 >>> 16 & 255, + h6 >>> 8 & 255, + h6 & 255 + ]; + if (!this.is224) arr.push(h7 >>> 24 & 255, h7 >>> 16 & 255, h7 >>> 8 & 255, h7 & 255); + return arr; }; - -Writer.prototype.getConfigEscape = function getConfigEscape (config) { - if (config && typeof config === 'object' && !mustache_isArray(config)) { - return config.escape; - } - else { - return undefined; - } +Sha256.prototype.array = Sha256.prototype.digest; +Sha256.prototype.arrayBuffer = function() { + this.finalize(); + var buffer = /* @__PURE__ */ new ArrayBuffer(this.is224 ? 28 : 32); + var dataView = new DataView(buffer); + dataView.setUint32(0, this.h0); + dataView.setUint32(4, this.h1); + dataView.setUint32(8, this.h2); + dataView.setUint32(12, this.h3); + dataView.setUint32(16, this.h4); + dataView.setUint32(20, this.h5); + dataView.setUint32(24, this.h6); + if (!this.is224) dataView.setUint32(28, this.h7); + return buffer; }; - -var mustache = { - name: 'mustache.js', - version: '4.2.0', - tags: [ '{{', '}}' ], - clearCache: undefined, - escape: undefined, - parse: undefined, - render: undefined, - Scanner: undefined, - Context: undefined, - Writer: undefined, - /** - * Allows a user to override the default caching strategy, by providing an - * object with set, get and clear methods. This can also be used to disable - * the cache by setting it to the literal `undefined`. - */ - set templateCache (cache) { - defaultWriter.templateCache = cache; - }, - /** - * Gets the default or overridden caching object from the default writer. - */ - get templateCache () { - return defaultWriter.templateCache; - } +const sha256 = (...strings) => { + return new Sha256(false, true).update(strings.join("")).hex(); }; -// All high-level mustache.* functions use this writer. -var defaultWriter = new Writer(); +//#endregion -/** - * Clears all cached templates in the default writer. - */ -mustache.clearCache = function clearCache () { - return defaultWriter.clearCache(); -}; +//# sourceMappingURL=hash.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/hash.js -/** - * Parses and caches the given template in the default writer and returns the - * array of tokens it contains. Doing this ahead of time avoids the need to - * parse templates on the fly as they are rendered. - */ -mustache.parse = function parse (template, tags) { - return defaultWriter.parse(template, tags); -}; -/** - * Renders the `template` with the given `view`, `partials`, and `config` - * using the default writer. - */ -mustache.render = function render (template, view, partials, config) { - if (typeof template !== 'string') { - throw new TypeError('Invalid template! Template should be a "string" ' + - 'but "' + typeStr(template) + '" was given as the first ' + - 'argument for mustache#render(template, view, partials)'); - } - return defaultWriter.render(template, view, partials, config); -}; +//#region src/utils/hash.ts +var hash_exports = {}; +__export(hash_exports, { sha256: () => sha256 }); -// Export the escaping function so that the user may override it. -// See https://github.com/janl/mustache.js/issues/244 -mustache.escape = escapeHtml; +//#endregion -// Export these mainly for testing, but also for advanced usage. -mustache.Scanner = Scanner; -mustache.Context = Context; -mustache.Writer = Writer; +//# sourceMappingURL=hash.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/caches/index.js -/* harmony default export */ const mustache_mustache = (mustache); -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/template.js -//#region src/prompts/template.ts -function configureMustache() { - mustache_mustache.escape = (text) => text; -} -const parseFString = (template) => { - const chars = template.split(""); - const nodes = []; - const nextBracket = (bracket, start) => { - for (let i$1 = start; i$1 < chars.length; i$1 += 1) if (bracket.includes(chars[i$1])) return i$1; - return -1; +//#region src/caches/index.ts +var caches_exports = {}; +__export(caches_exports, { + BaseCache: () => caches_BaseCache, + InMemoryCache: () => InMemoryCache, + defaultHashKeyEncoder: () => defaultHashKeyEncoder, + deserializeStoredGeneration: () => deserializeStoredGeneration, + serializeGeneration: () => serializeGeneration +}); +const defaultHashKeyEncoder = (...strings) => sha256(strings.join("_")); +function deserializeStoredGeneration(storedGeneration) { + if (storedGeneration.message !== void 0) return { + text: storedGeneration.text, + message: mapStoredMessageToChatMessage(storedGeneration.message) }; - let i = 0; - while (i < chars.length) if (chars[i] === "{" && i + 1 < chars.length && chars[i + 1] === "{") { - nodes.push({ - type: "literal", - text: "{" - }); - i += 2; - } else if (chars[i] === "}" && i + 1 < chars.length && chars[i + 1] === "}") { - nodes.push({ - type: "literal", - text: "}" - }); - i += 2; - } else if (chars[i] === "{") { - const j = nextBracket("}", i); - if (j < 0) throw new Error("Unclosed '{' in template."); - nodes.push({ - type: "variable", - name: chars.slice(i + 1, j).join("") - }); - i = j + 1; - } else if (chars[i] === "}") throw new Error("Single '}' in template."); - else { - const next = nextBracket("{}", i); - const text = (next < 0 ? chars.slice(i) : chars.slice(i, next)).join(""); - nodes.push({ - type: "literal", - text - }); - i = next < 0 ? chars.length : next; - } - return nodes; -}; + else return { text: storedGeneration.text }; +} +function serializeGeneration(generation) { + const serializedValue = { text: generation.text }; + if (generation.message !== void 0) serializedValue.message = generation.message.toDict(); + return serializedValue; +} /** -* Convert the result of mustache.parse into an array of ParsedTemplateNode, -* to make it compatible with other LangChain string parsing template formats. -* -* @param {mustache.TemplateSpans} template The result of parsing a mustache template with the mustache.js library. -* @param {string[]} context Array of section variable names for nested context -* @returns {ParsedTemplateNode[]} +* Base class for all caches. All caches should extend this class. */ -const mustacheTemplateToNodes = (template, context = []) => { - const nodes = []; - for (const temp of template) if (temp[0] === "name") { - const name = temp[1].includes(".") ? temp[1].split(".")[0] : temp[1]; - nodes.push({ - type: "variable", - name - }); - } else if ([ - "#", - "&", - "^", - ">" - ].includes(temp[0])) { - nodes.push({ - type: "variable", - name: temp[1] - }); - if (temp[0] === "#" && temp.length > 4 && Array.isArray(temp[4])) { - const newContext = [...context, temp[1]]; - const nestedNodes = mustacheTemplateToNodes(temp[4], newContext); - nodes.push(...nestedNodes); - } - } else nodes.push({ - type: "literal", - text: temp[1] - }); - return nodes; -}; -const parseMustache = (template) => { - configureMustache(); - const parsed = mustache_mustache.parse(template); - return mustacheTemplateToNodes(parsed); -}; -const interpolateFString = (template, values) => { - return parseFString(template).reduce((res, node) => { - if (node.type === "variable") { - if (node.name in values) { - const stringValue = typeof values[node.name] === "string" ? values[node.name] : JSON.stringify(values[node.name]); - return res + stringValue; - } - throw new Error(`(f-string) Missing value for input ${node.name}`); - } - return res + node.text; - }, ""); -}; -const interpolateMustache = (template, values) => { - configureMustache(); - return mustache_mustache.render(template, values); -}; -const DEFAULT_FORMATTER_MAPPING = { - "f-string": interpolateFString, - mustache: interpolateMustache -}; -const DEFAULT_PARSER_MAPPING = { - "f-string": parseFString, - mustache: parseMustache -}; -const renderTemplate = (template, templateFormat, inputValues) => { - try { - return DEFAULT_FORMATTER_MAPPING[templateFormat](template, inputValues); - } catch (e) { - const error = addLangChainErrorFields(e, "INVALID_PROMPT_INPUT"); - throw error; +var caches_BaseCache = class { + keyEncoder = defaultHashKeyEncoder; + /** + * Sets a custom key encoder function for the cache. + * This function should take a prompt and an LLM key and return a string + * that will be used as the cache key. + * @param keyEncoderFn The custom key encoder function. + */ + makeDefaultKeyEncoder(keyEncoderFn) { + this.keyEncoder = keyEncoderFn; } }; -const template_parseTemplate = (template, templateFormat) => DEFAULT_PARSER_MAPPING[templateFormat](template); -const checkValidTemplate = (template, templateFormat, inputVariables) => { - if (!(templateFormat in DEFAULT_FORMATTER_MAPPING)) { - const validFormats = Object.keys(DEFAULT_FORMATTER_MAPPING); - throw new Error(`Invalid template format. Got \`${templateFormat}\`; - should be one of ${validFormats}`); +const GLOBAL_MAP = /* @__PURE__ */ new Map(); +/** +* A cache for storing LLM generations that stores data in memory. +*/ +var InMemoryCache = class InMemoryCache extends caches_BaseCache { + cache; + constructor(map) { + super(); + this.cache = map ?? /* @__PURE__ */ new Map(); } - try { - const dummyInputs = inputVariables.reduce((acc, v) => { - acc[v] = "foo"; - return acc; - }, {}); - if (Array.isArray(template)) template.forEach((message) => { - if (message.type === "text" && "text" in message && typeof message.text === "string") renderTemplate(message.text, templateFormat, dummyInputs); - else if (message.type === "image_url") { - if (typeof message.image_url === "string") renderTemplate(message.image_url, templateFormat, dummyInputs); - else if (typeof message.image_url === "object" && message.image_url !== null && "url" in message.image_url && typeof message.image_url.url === "string") { - const imageUrl = message.image_url.url; - renderTemplate(imageUrl, templateFormat, dummyInputs); - } - } else throw new Error(`Invalid message template received. ${JSON.stringify(message, null, 2)}`); - }); - else renderTemplate(template, templateFormat, dummyInputs); - } catch (e) { - throw new Error(`Invalid prompt schema: ${e.message}`); + /** + * Retrieves data from the cache using a prompt and an LLM key. If the + * data is not found, it returns null. + * @param prompt The prompt used to find the data. + * @param llmKey The LLM key used to find the data. + * @returns The data corresponding to the prompt and LLM key, or null if not found. + */ + lookup(prompt, llmKey) { + return Promise.resolve(this.cache.get(this.keyEncoder(prompt, llmKey)) ?? null); + } + /** + * Updates the cache with new data using a prompt and an LLM key. + * @param prompt The prompt used to store the data. + * @param llmKey The LLM key used to store the data. + * @param value The data to be stored. + */ + async update(prompt, llmKey, value) { + this.cache.set(this.keyEncoder(prompt, llmKey), value); + } + /** + * Returns a global instance of InMemoryCache using a predefined global + * map as the initial cache. + * @returns A global instance of InMemoryCache. + */ + static global() { + return new InMemoryCache(GLOBAL_MAP); } }; //#endregion -//# sourceMappingURL=template.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/prompt.js +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/document_loaders/base.js +//#region src/document_loaders/base.ts +var document_loaders_base_base_exports = {}; +__export(document_loaders_base_base_exports, { BaseDocumentLoader: () => BaseDocumentLoader }); +/** +* Abstract class that provides a default implementation for the +* loadAndSplit() method from the DocumentLoader interface. The load() +* method is left abstract and needs to be implemented by subclasses. +*/ +var BaseDocumentLoader = class {}; -//#region src/prompts/prompt.ts +//#endregion + +//# sourceMappingURL=base.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/document_loaders/langsmith.js + + + + +//#region src/document_loaders/langsmith.ts +var langsmith_exports = {}; +__export(langsmith_exports, { LangSmithLoader: () => LangSmithLoader }); /** -* Schema to represent a basic prompt for an LLM. -* @augments BasePromptTemplate -* @augments PromptTemplateInput +* Document loader integration with LangSmith. * -* @example -* ```ts -* import { PromptTemplate } from "langchain/prompts"; +* ## [Constructor args](https://api.js.langchain.com/interfaces/_langchain_core.document_loaders_langsmith.LangSmithLoaderFields.html) * -* const prompt = new PromptTemplate({ -* inputVariables: ["foo"], -* template: "Say {foo}", +*
+* Load +* +* ```typescript +* import { LangSmithLoader } from '@langchain/core/document_loaders/langsmith'; +* import { Client } from 'langsmith'; +* +* const langSmithClient = new Client({ +* apiKey: process.env.LANGSMITH_API_KEY, +* }) +* +* const loader = new LangSmithLoader({ +* datasetId: "9a3b36f7-b308-40a5-9b46-6613853b6330", +* limit: 1, * }); +* +* const docs = await loader.load(); +* ``` +* +* ```txt +* [ +* { +* pageContent: '{\n "input_key_str": "string",\n "input_key_bool": true\n}', +* metadata: { +* id: '8523d9e9-c123-4b23-9b46-21021nds289e', +* created_at: '2024-08-19T17:09:14.806441+00:00', +* modified_at: '2024-08-19T17:09:14.806441+00:00', +* name: '#8517 @ brace-test-dataset', +* dataset_id: '9a3b36f7-b308-40a5-9b46-6613853b6330', +* source_run_id: null, +* metadata: [Object], +* inputs: [Object], +* outputs: [Object] +* } +* } +* ] * ``` +*
*/ -var PromptTemplate = class PromptTemplate extends BaseStringPromptTemplate { - static lc_name() { - return "PromptTemplate"; +var LangSmithLoader = class extends BaseDocumentLoader { + datasetId; + datasetName; + exampleIds; + asOf; + splits; + inlineS3Urls; + offset; + limit; + metadata; + filter; + contentKey; + formatContent; + client; + constructor(fields) { + super(); + if (fields.client && fields.clientConfig) throw new Error("client and clientConfig cannot both be provided."); + this.client = fields.client ?? new Client(fields?.clientConfig); + this.contentKey = fields.contentKey ? fields.contentKey.split(".") : []; + this.formatContent = fields.formatContent ?? _stringify; + this.datasetId = fields.datasetId; + this.datasetName = fields.datasetName; + this.exampleIds = fields.exampleIds; + this.asOf = fields.asOf; + this.splits = fields.splits; + this.inlineS3Urls = fields.inlineS3Urls; + this.offset = fields.offset; + this.limit = fields.limit; + this.metadata = fields.metadata; + this.filter = fields.filter; } - template; - templateFormat = "f-string"; - validateTemplate = true; - /** - * Additional fields which should be included inside - * the message content array if using a complex message - * content. - */ - additionalContentFields; - constructor(input) { - super(input); - if (input.templateFormat === "mustache" && input.validateTemplate === void 0) this.validateTemplate = false; - Object.assign(this, input); - if (this.validateTemplate) { - if (this.templateFormat === "mustache") throw new Error("Mustache templates cannot be validated."); - let totalInputVariables = this.inputVariables; - if (this.partialVariables) totalInputVariables = totalInputVariables.concat(Object.keys(this.partialVariables)); - checkValidTemplate(this.template, this.templateFormat, totalInputVariables); + async load() { + const documents = []; + for await (const example of this.client.listExamples({ + datasetId: this.datasetId, + datasetName: this.datasetName, + exampleIds: this.exampleIds, + asOf: this.asOf, + splits: this.splits, + inlineS3Urls: this.inlineS3Urls, + offset: this.offset, + limit: this.limit, + metadata: this.metadata, + filter: this.filter + })) { + let content = example.inputs; + for (const key of this.contentKey) content = content[key]; + const contentStr = this.formatContent(content); + const metadata = example; + ["created_at", "modified_at"].forEach((k) => { + if (k in metadata) { + if (typeof metadata[k] === "object") metadata[k] = metadata[k].toString(); + } + }); + documents.push({ + pageContent: contentStr, + metadata + }); } + return documents; } - _getPromptType() { - return "prompt"; - } - /** - * Formats the prompt template with the provided values. - * @param values The values to be used to format the prompt template. - * @returns A promise that resolves to a string which is the formatted prompt. - */ - async format(values) { - const allValues = await this.mergePartialAndUserVariables(values); - return renderTemplate(this.template, this.templateFormat, allValues); +}; +function _stringify(x) { + if (typeof x === "string") return x; + else try { + return JSON.stringify(x, null, 2); + } catch { + return String(x); } +} + +//#endregion + +//# sourceMappingURL=langsmith.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/documents/document.js +//#region src/documents/document.ts +/** +* Interface for interacting with a document. +*/ +var Document = class { + pageContent; + metadata; /** - * Take examples in list format with prefix and suffix to create a prompt. - * - * Intended to be used a a way to dynamically create a prompt from examples. - * - * @param examples - List of examples to use in the prompt. - * @param suffix - String to go after the list of examples. Should generally set up the user's input. - * @param inputVariables - A list of variable names the final prompt template will expect - * @param exampleSeparator - The separator to use in between examples - * @param prefix - String that should go before any examples. Generally includes examples. + * An optional identifier for the document. * - * @returns The final prompt template generated. + * Ideally this should be unique across the document collection and formatted + * as a UUID, but this will not be enforced. */ - static fromExamples(examples, suffix, inputVariables, exampleSeparator = "\n\n", prefix = "") { - const template = [ - prefix, - ...examples, - suffix - ].join(exampleSeparator); - return new PromptTemplate({ - inputVariables, - template - }); - } - static fromTemplate(template, options) { - const { templateFormat = "f-string",...rest } = options ?? {}; - const names = /* @__PURE__ */ new Set(); - template_parseTemplate(template, templateFormat).forEach((node) => { - if (node.type === "variable") names.add(node.name); - }); - return new PromptTemplate({ - inputVariables: [...names], - templateFormat, - template, - ...rest - }); + id; + constructor(fields) { + this.pageContent = fields.pageContent !== void 0 ? fields.pageContent.toString() : ""; + this.metadata = fields.metadata ?? {}; + this.id = fields.id; } +}; + +//#endregion + +//# sourceMappingURL=document.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/documents/transformers.js + + +//#region src/documents/transformers.ts +/** +* Abstract base class for document transformation systems. +* +* A document transformation system takes an array of Documents and returns an +* array of transformed Documents. These arrays do not necessarily have to have +* the same length. +* +* One example of this is a text splitter that splits a large document into +* many smaller documents. +*/ +var BaseDocumentTransformer = class extends Runnable { + lc_namespace = [ + "langchain_core", + "documents", + "transformers" + ]; /** - * Partially applies values to the prompt template. - * @param values The values to be partially applied to the prompt template. - * @returns A new instance of PromptTemplate with the partially applied values. + * Method to invoke the document transformation. This method calls the + * transformDocuments method with the provided input. + * @param input The input documents to be transformed. + * @param _options Optional configuration object to customize the behavior of callbacks. + * @returns A Promise that resolves to the transformed documents. */ - async partial(values) { - const newInputVariables = this.inputVariables.filter((iv) => !(iv in values)); - const newPartialVariables = { - ...this.partialVariables ?? {}, - ...values - }; - const promptDict = { - ...this, - inputVariables: newInputVariables, - partialVariables: newPartialVariables - }; - return new PromptTemplate(promptDict); - } - serialize() { - if (this.outputParser !== void 0) throw new Error("Cannot serialize a prompt template with an output parser"); - return { - _type: this._getPromptType(), - input_variables: this.inputVariables, - template: this.template, - template_format: this.templateFormat - }; + invoke(input, _options) { + return this.transformDocuments(input); } - static async deserialize(data) { - if (!data.template) throw new Error("Prompt template must have a template"); - const res = new PromptTemplate({ - inputVariables: data.input_variables, - template: data.template, - templateFormat: data.template_format - }); - return res; +}; +/** +* Class for document transformers that return exactly one transformed document +* for each input document. +*/ +var MappingDocumentTransformer = class extends BaseDocumentTransformer { + async transformDocuments(documents) { + const newDocuments = []; + for (const document of documents) { + const transformedDocument = await this._transformDocument(document); + newDocuments.push(transformedDocument); + } + return newDocuments; } }; //#endregion -//# sourceMappingURL=prompt.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/image.js +//# sourceMappingURL=transformers.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/documents/index.js -//#region src/prompts/image.ts +//#region src/documents/index.ts +var documents_exports = {}; +__export(documents_exports, { + BaseDocumentTransformer: () => BaseDocumentTransformer, + Document: () => Document, + MappingDocumentTransformer: () => MappingDocumentTransformer +}); + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/base.js + + +//#region src/example_selectors/base.ts /** -* An image prompt template for a multimodal model. +* Base class for example selectors. */ -var ImagePromptTemplate = class ImagePromptTemplate extends BasePromptTemplate { - static lc_name() { - return "ImagePromptTemplate"; - } +var BaseExampleSelector = class extends Serializable { lc_namespace = [ "langchain_core", - "prompts", - "image" + "example_selectors", + "base" ]; - template; - templateFormat = "f-string"; - validateTemplate = true; +}; + +//#endregion + +//# sourceMappingURL=base.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/conditional.js +//#region src/example_selectors/conditional.ts +/** +* Abstract class that defines the interface for selecting a prompt for a +* given language model. +*/ +var BasePromptSelector = class { /** - * Additional fields which should be included inside - * the message content array if using a complex message - * content. + * Asynchronous version of `getPrompt` that also accepts an options object + * for partial variables. + * @param llm The language model for which to get a prompt. + * @param options Optional object for partial variables. + * @returns A Promise that resolves to a prompt template. */ - additionalContentFields; - constructor(input) { - super(input); - this.template = input.template; - this.templateFormat = input.templateFormat ?? this.templateFormat; - this.validateTemplate = input.validateTemplate ?? this.validateTemplate; - this.additionalContentFields = input.additionalContentFields; - if (this.validateTemplate) { - let totalInputVariables = this.inputVariables; - if (this.partialVariables) totalInputVariables = totalInputVariables.concat(Object.keys(this.partialVariables)); - checkValidTemplate([{ - type: "image_url", - image_url: this.template - }], this.templateFormat, totalInputVariables); - } + async getPromptAsync(llm, options) { + const prompt = this.getPrompt(llm); + return prompt.partial(options?.partialVariables ?? {}); } - _getPromptType() { - return "prompt"; +}; +/** +* Concrete implementation of `BasePromptSelector` that selects a prompt +* based on a set of conditions. It has a default prompt that it returns +* if none of the conditions are met. +*/ +var ConditionalPromptSelector = class extends BasePromptSelector { + defaultPrompt; + conditionals; + constructor(default_prompt, conditionals = []) { + super(); + this.defaultPrompt = default_prompt; + this.conditionals = conditionals; } /** - * Partially applies values to the prompt template. - * @param values The values to be partially applied to the prompt template. - * @returns A new instance of ImagePromptTemplate with the partially applied values. + * Method that selects a prompt based on a set of conditions. If none of + * the conditions are met, it returns the default prompt. + * @param llm The language model for which to get a prompt. + * @returns A prompt template. + */ + getPrompt(llm) { + for (const [condition, prompt] of this.conditionals) if (condition(llm)) return prompt; + return this.defaultPrompt; + } +}; +/** +* Type guard function that checks if a given language model is of type +* `BaseLLM`. +*/ +function isLLM(llm) { + return llm._modelType() === "base_llm"; +} +/** +* Type guard function that checks if a given language model is of type +* `BaseChatModel`. +*/ +function isChatModel(llm) { + return llm._modelType() === "base_chat_model"; +} + +//#endregion + +//# sourceMappingURL=conditional.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/length_based.js + + +//#region src/example_selectors/length_based.ts +/** +* Calculates the length of a text based on the number of words and lines. +*/ +function getLengthBased(text) { + return text.split(/\n| /).length; +} +/** +* A specialized example selector that selects examples based on their +* length, ensuring that the total length of the selected examples does +* not exceed a specified maximum length. +* @example +* ```typescript +* const exampleSelector = new LengthBasedExampleSelector( +* [ +* { input: "happy", output: "sad" }, +* { input: "tall", output: "short" }, +* { input: "energetic", output: "lethargic" }, +* { input: "sunny", output: "gloomy" }, +* { input: "windy", output: "calm" }, +* ], +* { +* examplePrompt: new PromptTemplate({ +* inputVariables: ["input", "output"], +* template: "Input: {input}\nOutput: {output}", +* }), +* maxLength: 25, +* }, +* ); +* const dynamicPrompt = new FewShotPromptTemplate({ +* exampleSelector, +* examplePrompt: new PromptTemplate({ +* inputVariables: ["input", "output"], +* template: "Input: {input}\nOutput: {output}", +* }), +* prefix: "Give the antonym of every input", +* suffix: "Input: {adjective}\nOutput:", +* inputVariables: ["adjective"], +* }); +* console.log(dynamicPrompt.format({ adjective: "big" })); +* console.log( +* dynamicPrompt.format({ +* adjective: +* "big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else", +* }), +* ); +* ``` +*/ +var LengthBasedExampleSelector = class LengthBasedExampleSelector extends BaseExampleSelector { + examples = []; + examplePrompt; + getTextLength = getLengthBased; + maxLength = 2048; + exampleTextLengths = []; + constructor(data) { + super(data); + this.examplePrompt = data.examplePrompt; + this.maxLength = data.maxLength ?? 2048; + this.getTextLength = data.getTextLength ?? getLengthBased; + } + /** + * Adds an example to the list of examples and calculates its length. + * @param example The example to be added. + * @returns Promise that resolves when the example has been added and its length calculated. + */ + async addExample(example) { + this.examples.push(example); + const stringExample = await this.examplePrompt.format(example); + this.exampleTextLengths.push(this.getTextLength(stringExample)); + } + /** + * Calculates the lengths of the examples. + * @param v Array of lengths of the examples. + * @param values Instance of LengthBasedExampleSelector. + * @returns Promise that resolves with an array of lengths of the examples. */ - async partial(values) { - const newInputVariables = this.inputVariables.filter((iv) => !(iv in values)); - const newPartialVariables = { - ...this.partialVariables ?? {}, - ...values - }; - const promptDict = { - ...this, - inputVariables: newInputVariables, - partialVariables: newPartialVariables - }; - return new ImagePromptTemplate(promptDict); + async calculateExampleTextLengths(v, values) { + if (v.length > 0) return v; + const { examples, examplePrompt } = values; + const stringExamples = await Promise.all(examples.map((eg) => examplePrompt.format(eg))); + return stringExamples.map((eg) => this.getTextLength(eg)); } /** - * Formats the prompt template with the provided values. - * @param values The values to be used to format the prompt template. - * @returns A promise that resolves to a string which is the formatted prompt. + * Selects examples until the total length of the selected examples + * reaches the maxLength. + * @param inputVariables The input variables for the examples. + * @returns Promise that resolves with an array of selected examples. */ - async format(values) { - const formatted = {}; - for (const [key, value] of Object.entries(this.template)) if (typeof value === "string") formatted[key] = renderTemplate(value, this.templateFormat, values); - else formatted[key] = value; - const url = values.url || formatted.url; - const detail = values.detail || formatted.detail; - if (!url) throw new Error("Must provide either an image URL."); - if (typeof url !== "string") throw new Error("url must be a string."); - const output = { url }; - if (detail) output.detail = detail; - return output; + async selectExamples(inputVariables) { + const inputs = Object.values(inputVariables).join(" "); + let remainingLength = this.maxLength - this.getTextLength(inputs); + let i = 0; + const examples = []; + while (remainingLength > 0 && i < this.examples.length) { + const newLength = remainingLength - this.exampleTextLengths[i]; + if (newLength < 0) break; + else { + examples.push(this.examples[i]); + remainingLength = newLength; + } + i += 1; + } + return examples; } /** - * Formats the prompt given the input values and returns a formatted - * prompt value. - * @param values The input values to format the prompt. - * @returns A Promise that resolves to a formatted prompt value. + * Creates a new instance of LengthBasedExampleSelector and adds a list of + * examples to it. + * @param examples Array of examples to be added. + * @param args Input parameters for the LengthBasedExampleSelector. + * @returns Promise that resolves with a new instance of LengthBasedExampleSelector with the examples added. */ - async formatPromptValue(values) { - const formattedPrompt = await this.format(values); - return new ImagePromptValue(formattedPrompt); + static async fromExamples(examples, args) { + const selector = new LengthBasedExampleSelector(args); + await Promise.all(examples.map((eg) => selector.addExample(eg))); + return selector; } }; //#endregion -//# sourceMappingURL=image.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/dict.js +//# sourceMappingURL=length_based.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/semantic_similarity.js -//#region src/prompts/dict.ts -var DictPromptTemplate = class extends Runnable { - lc_namespace = [ - "langchain_core", - "prompts", - "dict" - ]; - lc_serializable = true; - template; - templateFormat; - inputVariables; - static lc_name() { - return "DictPromptTemplate"; - } - constructor(fields) { - const templateFormat = fields.templateFormat ?? "f-string"; - const inputVariables = _getInputVariables(fields.template, templateFormat); - super({ - inputVariables, - ...fields +//#region src/example_selectors/semantic_similarity.ts +function sortedValues(values) { + return Object.keys(values).sort().map((key) => values[key]); +} +/** +* Class that selects examples based on semantic similarity. It extends +* the BaseExampleSelector class. +* @example +* ```typescript +* const exampleSelector = await SemanticSimilarityExampleSelector.fromExamples( +* [ +* { input: "happy", output: "sad" }, +* { input: "tall", output: "short" }, +* { input: "energetic", output: "lethargic" }, +* { input: "sunny", output: "gloomy" }, +* { input: "windy", output: "calm" }, +* ], +* new OpenAIEmbeddings(), +* HNSWLib, +* { k: 1 }, +* ); +* const dynamicPrompt = new FewShotPromptTemplate({ +* exampleSelector, +* examplePrompt: PromptTemplate.fromTemplate( +* "Input: {input}\nOutput: {output}", +* ), +* prefix: "Give the antonym of every input", +* suffix: "Input: {adjective}\nOutput:", +* inputVariables: ["adjective"], +* }); +* console.log(await dynamicPrompt.format({ adjective: "rainy" })); +* ``` +*/ +var SemanticSimilarityExampleSelector = class SemanticSimilarityExampleSelector extends BaseExampleSelector { + vectorStoreRetriever; + exampleKeys; + inputKeys; + constructor(data) { + super(data); + this.exampleKeys = data.exampleKeys; + this.inputKeys = data.inputKeys; + if (data.vectorStore !== void 0) this.vectorStoreRetriever = data.vectorStore.asRetriever({ + k: data.k ?? 4, + filter: data.filter }); - this.template = fields.template; - this.templateFormat = templateFormat; - this.inputVariables = inputVariables; + else if (data.vectorStoreRetriever) this.vectorStoreRetriever = data.vectorStoreRetriever; + else throw new Error(`You must specify one of "vectorStore" and "vectorStoreRetriever".`); } - async format(values) { - return _insertInputVariables(this.template, values, this.templateFormat); + /** + * Method that adds a new example to the vectorStore. The example is + * converted to a string and added to the vectorStore as a document. + * @param example The example to be added to the vectorStore. + * @returns Promise that resolves when the example has been added to the vectorStore. + */ + async addExample(example) { + const inputKeys = this.inputKeys ?? Object.keys(example); + const stringExample = sortedValues(inputKeys.reduce((acc, key) => ({ + ...acc, + [key]: example[key] + }), {})).join(" "); + await this.vectorStoreRetriever.addDocuments([new Document({ + pageContent: stringExample, + metadata: example + })]); } - async invoke(values) { - return await this._callWithConfig(this.format.bind(this), values, { runType: "prompt" }); + /** + * Method that selects which examples to use based on semantic similarity. + * It performs a similarity search in the vectorStore using the input + * variables and returns the examples with the highest similarity. + * @param inputVariables The input variables used for the similarity search. + * @returns Promise that resolves with an array of the selected examples. + */ + async selectExamples(inputVariables) { + const inputKeys = this.inputKeys ?? Object.keys(inputVariables); + const query = sortedValues(inputKeys.reduce((acc, key) => ({ + ...acc, + [key]: inputVariables[key] + }), {})).join(" "); + const exampleDocs = await this.vectorStoreRetriever.invoke(query); + const examples = exampleDocs.map((doc) => doc.metadata); + if (this.exampleKeys) return examples.map((example) => this.exampleKeys.reduce((acc, key) => ({ + ...acc, + [key]: example[key] + }), {})); + return examples; } -}; -function _getInputVariables(template, templateFormat) { - const inputVariables = []; - for (const v of Object.values(template)) if (typeof v === "string") template_parseTemplate(v, templateFormat).forEach((t) => { - if (t.type === "variable") inputVariables.push(t.name); - }); - else if (Array.isArray(v)) { - for (const x of v) if (typeof x === "string") template_parseTemplate(x, templateFormat).forEach((t) => { - if (t.type === "variable") inputVariables.push(t.name); + /** + * Static method that creates a new instance of + * SemanticSimilarityExampleSelector. It takes a list of examples, an + * instance of Embeddings, a VectorStore class, and an options object as + * parameters. It converts the examples to strings, creates a VectorStore + * from the strings and the embeddings, and returns a new + * SemanticSimilarityExampleSelector with the created VectorStore and the + * options provided. + * @param examples The list of examples to be used. + * @param embeddings The instance of Embeddings to be used. + * @param vectorStoreCls The VectorStore class to be used. + * @param options The options object for the SemanticSimilarityExampleSelector. + * @returns Promise that resolves with a new instance of SemanticSimilarityExampleSelector. + */ + static async fromExamples(examples, embeddings, vectorStoreCls, options = {}) { + const inputKeys = options.inputKeys ?? null; + const stringExamples = examples.map((example) => sortedValues(inputKeys ? inputKeys.reduce((acc, key) => ({ + ...acc, + [key]: example[key] + }), {}) : example).join(" ")); + const vectorStore = await vectorStoreCls.fromTexts(stringExamples, examples, embeddings, options); + return new SemanticSimilarityExampleSelector({ + vectorStore, + k: options.k ?? 4, + exampleKeys: options.exampleKeys, + inputKeys: options.inputKeys }); - else if (typeof x === "object") inputVariables.push(..._getInputVariables(x, templateFormat)); - } else if (typeof v === "object" && v !== null) inputVariables.push(..._getInputVariables(v, templateFormat)); - return Array.from(new Set(inputVariables)); -} -function _insertInputVariables(template, inputs, templateFormat) { - const formatted = {}; - for (const [k, v] of Object.entries(template)) if (typeof v === "string") formatted[k] = renderTemplate(v, templateFormat, inputs); - else if (Array.isArray(v)) { - const formattedV = []; - for (const x of v) if (typeof x === "string") formattedV.push(renderTemplate(x, templateFormat, inputs)); - else if (typeof x === "object") formattedV.push(_insertInputVariables(x, inputs, templateFormat)); - formatted[k] = formattedV; - } else if (typeof v === "object" && v !== null) formatted[k] = _insertInputVariables(v, inputs, templateFormat); - else formatted[k] = v; - return formatted; -} + } +}; //#endregion -//# sourceMappingURL=dict.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/chat.js +//# sourceMappingURL=semantic_similarity.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/example_selectors/index.js +//#region src/example_selectors/index.ts +var example_selectors_exports = {}; +__export(example_selectors_exports, { + BaseExampleSelector: () => BaseExampleSelector, + BasePromptSelector: () => BasePromptSelector, + ConditionalPromptSelector: () => ConditionalPromptSelector, + LengthBasedExampleSelector: () => LengthBasedExampleSelector, + SemanticSimilarityExampleSelector: () => SemanticSimilarityExampleSelector, + isChatModel: () => isChatModel, + isLLM: () => isLLM +}); + +//#endregion +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/indexing/record_manager.js +//#region src/indexing/record_manager.ts +const UUIDV5_NAMESPACE = "10f90ea3-90a4-4962-bf75-83a0f3c1c62a"; +var RecordManager = class extends Serializable { + lc_namespace = ["langchain", "recordmanagers"]; +}; +//#endregion +//# sourceMappingURL=record_manager.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/indexing/base.js -//#region src/prompts/chat.ts -/** -* Abstract class that serves as a base for creating message prompt -* templates. It defines how to format messages for different roles in a -* conversation. -*/ -var BaseMessagePromptTemplate = class extends Runnable { - lc_namespace = [ - "langchain_core", - "prompts", - "chat" - ]; - lc_serializable = true; - /** - * Calls the formatMessages method with the provided input and options. - * @param input Input for the formatMessages method - * @param options Optional BaseCallbackConfig - * @returns Formatted output messages - */ - async invoke(input, options) { - return this._callWithConfig((input$1) => this.formatMessages(input$1), input, { - ...options, - runType: "prompt" - }); - } -}; +//#region src/indexing/base.ts /** -* Class that represents a placeholder for messages in a chat prompt. It -* extends the BaseMessagePromptTemplate. +* HashedDocument is a Document with hashes calculated. +* Hashes are calculated based on page content and metadata. +* It is used for indexing. */ -var MessagesPlaceholder = class extends BaseMessagePromptTemplate { - static lc_name() { - return "MessagesPlaceholder"; - } - variableName; - optional; +var _HashedDocument = class { + uid; + hash_; + contentHash; + metadataHash; + pageContent; + metadata; + keyEncoder = sha256; constructor(fields) { - if (typeof fields === "string") fields = { variableName: fields }; - super(fields); - this.variableName = fields.variableName; - this.optional = fields.optional ?? false; + this.uid = fields.uid; + this.pageContent = fields.pageContent; + this.metadata = fields.metadata; } - get inputVariables() { - return [this.variableName]; + makeDefaultKeyEncoder(keyEncoderFn) { + this.keyEncoder = keyEncoderFn; } - async formatMessages(values) { - const input = values[this.variableName]; - if (this.optional && !input) return []; - else if (!input) { - const error = /* @__PURE__ */ new Error(`Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages as an input value. Received: undefined`); - error.name = "InputFormatError"; - throw error; - } - let formattedMessages; + calculateHashes() { + const forbiddenKeys = [ + "hash_", + "content_hash", + "metadata_hash" + ]; + for (const key of forbiddenKeys) if (key in this.metadata) throw new Error(`Metadata cannot contain key ${key} as it is reserved for internal use. Restricted keys: [${forbiddenKeys.join(", ")}]`); + const contentHash = this._hashStringToUUID(this.pageContent); try { - if (Array.isArray(input)) formattedMessages = input.map(utils_coerceMessageLikeToMessage); - else formattedMessages = [utils_coerceMessageLikeToMessage(input)]; + const metadataHash = this._hashNestedDictToUUID(this.metadata); + this.contentHash = contentHash; + this.metadataHash = metadataHash; } catch (e) { - const readableInput = typeof input === "string" ? input : JSON.stringify(input, null, 2); - const error = new Error([ - `Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages or coerceable values as input.`, - `Received value: ${readableInput}`, - `Additional message: ${e.message}` - ].join("\n\n")); - error.name = "InputFormatError"; - error.lc_error_code = e.lc_error_code; - throw error; + throw new Error(`Failed to hash metadata: ${e}. Please use a dict that can be serialized using json.`); } - return formattedMessages; - } -}; -/** -* Abstract class that serves as a base for creating message string prompt -* templates. It extends the BaseMessagePromptTemplate. -*/ -var BaseMessageStringPromptTemplate = class extends BaseMessagePromptTemplate { - prompt; - constructor(fields) { - if (!("prompt" in fields)) fields = { prompt: fields }; - super(fields); - this.prompt = fields.prompt; - } - get inputVariables() { - return this.prompt.inputVariables; + this.hash_ = this._hashStringToUUID(this.contentHash + this.metadataHash); + if (!this.uid) this.uid = this.hash_; } - async formatMessages(values) { - return [await this.format(values)]; + toDocument() { + return new Document({ + pageContent: this.pageContent, + metadata: this.metadata + }); } -}; -/** -* Abstract class that serves as a base for creating chat prompt -* templates. It extends the BasePromptTemplate. -*/ -var BaseChatPromptTemplate = class extends BasePromptTemplate { - constructor(input) { - super(input); + static fromDocument(document, uid) { + const doc = new this({ + pageContent: document.pageContent, + metadata: document.metadata, + uid: uid || document.uid + }); + doc.calculateHashes(); + return doc; } - async format(values) { - return (await this.formatPromptValue(values)).toString(); + _hashStringToUUID(inputString) { + const hash_value = this.keyEncoder(inputString); + return v5(hash_value, UUIDV5_NAMESPACE); } - async formatPromptValue(values) { - const resultMessages = await this.formatMessages(values); - return new ChatPromptValue(resultMessages); + _hashNestedDictToUUID(data) { + const serialized_data = JSON.stringify(data, Object.keys(data).sort()); + const hash_value = this.keyEncoder(serialized_data); + return v5(hash_value, UUIDV5_NAMESPACE); } }; -/** -* Class that represents a chat message prompt template. It extends the -* BaseMessageStringPromptTemplate. -*/ -var ChatMessagePromptTemplate = class extends BaseMessageStringPromptTemplate { - static lc_name() { - return "ChatMessagePromptTemplate"; - } - role; - constructor(fields, role) { - if (!("prompt" in fields)) fields = { - prompt: fields, - role - }; - super(fields); - this.role = fields.role; - } - async format(values) { - return new ChatMessage(await this.prompt.format(values), this.role); - } - static fromTemplate(template, role, options) { - return new this(PromptTemplate.fromTemplate(template, { templateFormat: options?.templateFormat }), role); +function _batch(size, iterable) { + const batches = []; + let currentBatch = []; + iterable.forEach((item) => { + currentBatch.push(item); + if (currentBatch.length >= size) { + batches.push(currentBatch); + currentBatch = []; + } + }); + if (currentBatch.length > 0) batches.push(currentBatch); + return batches; +} +function _deduplicateInOrder(hashedDocuments) { + const seen = /* @__PURE__ */ new Set(); + const deduplicated = []; + for (const hashedDoc of hashedDocuments) { + if (!hashedDoc.hash_) throw new Error("Hashed document does not have a hash"); + if (!seen.has(hashedDoc.hash_)) { + seen.add(hashedDoc.hash_); + deduplicated.push(hashedDoc); + } } -}; -function isTextTemplateParam(param) { - if (param === null || typeof param !== "object" || Array.isArray(param)) return false; - return Object.keys(param).length === 1 && "text" in param && typeof param.text === "string"; + return deduplicated; } -function isImageTemplateParam(param) { - if (param === null || typeof param !== "object" || Array.isArray(param)) return false; - return "image_url" in param && (typeof param.image_url === "string" || typeof param.image_url === "object" && param.image_url !== null && "url" in param.image_url && typeof param.image_url.url === "string"); +function _getSourceIdAssigner(sourceIdKey) { + if (sourceIdKey === null) return (_doc) => null; + else if (typeof sourceIdKey === "string") return (doc) => doc.metadata[sourceIdKey]; + else if (typeof sourceIdKey === "function") return sourceIdKey; + else throw new Error(`sourceIdKey should be null, a string or a function, got ${typeof sourceIdKey}`); } -var _StringImageMessagePromptTemplate = class extends BaseMessagePromptTemplate { - lc_namespace = [ - "langchain_core", - "prompts", - "chat" - ]; - lc_serializable = true; - inputVariables = []; - additionalOptions = {}; - prompt; - messageClass; - static _messageClass() { - throw new Error("Can not invoke _messageClass from inside _StringImageMessagePromptTemplate"); - } - chatMessageClass; - constructor(fields, additionalOptions) { - if (!("prompt" in fields)) fields = { prompt: fields }; - super(fields); - this.prompt = fields.prompt; - if (Array.isArray(this.prompt)) { - let inputVariables = []; - this.prompt.forEach((prompt) => { - if ("inputVariables" in prompt) inputVariables = inputVariables.concat(prompt.inputVariables); +const _isBaseDocumentLoader = (arg) => { + if ("load" in arg && typeof arg.load === "function" && "loadAndSplit" in arg && typeof arg.loadAndSplit === "function") return true; + return false; +}; +/** +* Index data from the doc source into the vector store. +* +* Indexing functionality uses a manager to keep track of which documents +* are in the vector store. +* +* This allows us to keep track of which documents were updated, and which +* documents were deleted, which documents should be skipped. +* +* For the time being, documents are indexed using their hashes, and users +* are not able to specify the uid of the document. +* +* @param {IndexArgs} args +* @param {BaseDocumentLoader | DocumentInterface[]} args.docsSource The source of documents to index. Can be a DocumentLoader or a list of Documents. +* @param {RecordManagerInterface} args.recordManager The record manager to use for keeping track of indexed documents. +* @param {VectorStore} args.vectorStore The vector store to use for storing the documents. +* @param {IndexOptions | undefined} args.options Options for indexing. +* @returns {Promise} +*/ +async function index(args) { + const { docsSource, recordManager, vectorStore, options } = args; + const { batchSize = 100, cleanup, sourceIdKey, cleanupBatchSize = 1e3, forceUpdate = false } = options ?? {}; + if (cleanup === "incremental" && !sourceIdKey) throw new Error("sourceIdKey is required when cleanup mode is incremental. Please provide through 'options.sourceIdKey'."); + const docs = _isBaseDocumentLoader(docsSource) ? await docsSource.load() : docsSource; + const sourceIdAssigner = _getSourceIdAssigner(sourceIdKey ?? null); + const indexStartDt = await recordManager.getTime(); + let numAdded = 0; + let numDeleted = 0; + let numUpdated = 0; + let numSkipped = 0; + const batches = _batch(batchSize ?? 100, docs); + for (const batch of batches) { + const hashedDocs = _deduplicateInOrder(batch.map((doc) => _HashedDocument.fromDocument(doc))); + const sourceIds = hashedDocs.map((doc) => sourceIdAssigner(doc)); + if (cleanup === "incremental") hashedDocs.forEach((_hashedDoc, index$1) => { + const source = sourceIds[index$1]; + if (source === null) throw new Error("sourceIdKey must be provided when cleanup is incremental"); + }); + const batchExists = await recordManager.exists(hashedDocs.map((doc) => doc.uid)); + const uids = []; + const docsToIndex = []; + const docsToUpdate = []; + const seenDocs = /* @__PURE__ */ new Set(); + hashedDocs.forEach((hashedDoc, i) => { + const docExists = batchExists[i]; + if (docExists) if (forceUpdate) seenDocs.add(hashedDoc.uid); + else { + docsToUpdate.push(hashedDoc.uid); + return; + } + uids.push(hashedDoc.uid); + docsToIndex.push(hashedDoc.toDocument()); + }); + if (docsToUpdate.length > 0) { + await recordManager.update(docsToUpdate, { timeAtLeast: indexStartDt }); + numSkipped += docsToUpdate.length; + } + if (docsToIndex.length > 0) { + await vectorStore.addDocuments(docsToIndex, { ids: uids }); + numAdded += docsToIndex.length - seenDocs.size; + numUpdated += seenDocs.size; + } + await recordManager.update(hashedDocs.map((doc) => doc.uid), { + timeAtLeast: indexStartDt, + groupIds: sourceIds + }); + if (cleanup === "incremental") { + sourceIds.forEach((sourceId) => { + if (!sourceId) throw new Error("Source id cannot be null"); }); - this.inputVariables = inputVariables; - } else this.inputVariables = this.prompt.inputVariables; - this.additionalOptions = additionalOptions ?? this.additionalOptions; - } - createMessage(content) { - const constructor = this.constructor; - if (constructor._messageClass()) { - const MsgClass = constructor._messageClass(); - return new MsgClass({ content }); - } else if (constructor.chatMessageClass) { - const MsgClass = constructor.chatMessageClass(); - return new MsgClass({ - content, - role: this.getRoleFromMessageClass(MsgClass.lc_name()) + const uidsToDelete = await recordManager.listKeys({ + before: indexStartDt, + groupIds: sourceIds }); - } else throw new Error("No message class defined"); - } - getRoleFromMessageClass(name) { - switch (name) { - case "HumanMessage": return "human"; - case "AIMessage": return "ai"; - case "SystemMessage": return "system"; - case "ChatMessage": return "chat"; - default: throw new Error("Invalid message class name"); + if (uidsToDelete.length > 0) { + await vectorStore.delete({ ids: uidsToDelete }); + await recordManager.deleteKeys(uidsToDelete); + numDeleted += uidsToDelete.length; + } } } - static fromTemplate(template, additionalOptions) { - if (typeof template === "string") return new this(PromptTemplate.fromTemplate(template, additionalOptions)); - const prompt = []; - for (const item of template) if (typeof item === "string") prompt.push(PromptTemplate.fromTemplate(item, additionalOptions)); - else if (item === null) {} else if (isTextTemplateParam(item)) { - let text = ""; - if (typeof item.text === "string") text = item.text ?? ""; - const options = { - ...additionalOptions, - additionalContentFields: item - }; - prompt.push(PromptTemplate.fromTemplate(text, options)); - } else if (isImageTemplateParam(item)) { - let imgTemplate = item.image_url ?? ""; - let imgTemplateObject; - let inputVariables = []; - if (typeof imgTemplate === "string") { - let parsedTemplate; - if (additionalOptions?.templateFormat === "mustache") parsedTemplate = parseMustache(imgTemplate); - else parsedTemplate = parseFString(imgTemplate); - const variables = parsedTemplate.flatMap((item$1) => item$1.type === "variable" ? [item$1.name] : []); - if ((variables?.length ?? 0) > 0) { - if (variables.length > 1) throw new Error(`Only one format variable allowed per image template.\nGot: ${variables}\nFrom: ${imgTemplate}`); - inputVariables = [variables[0]]; - } else inputVariables = []; - imgTemplate = { url: imgTemplate }; - imgTemplateObject = new ImagePromptTemplate({ - template: imgTemplate, - inputVariables, - templateFormat: additionalOptions?.templateFormat, - additionalContentFields: item - }); - } else if (typeof imgTemplate === "object") { - if ("url" in imgTemplate) { - let parsedTemplate; - if (additionalOptions?.templateFormat === "mustache") parsedTemplate = parseMustache(imgTemplate.url); - else parsedTemplate = parseFString(imgTemplate.url); - inputVariables = parsedTemplate.flatMap((item$1) => item$1.type === "variable" ? [item$1.name] : []); - } else inputVariables = []; - imgTemplateObject = new ImagePromptTemplate({ - template: imgTemplate, - inputVariables, - templateFormat: additionalOptions?.templateFormat, - additionalContentFields: item - }); - } else throw new Error("Invalid image template"); - prompt.push(imgTemplateObject); - } else if (typeof item === "object") prompt.push(new DictPromptTemplate({ - template: item, - templateFormat: additionalOptions?.templateFormat - })); - return new this({ - prompt, - additionalOptions + if (cleanup === "full") { + let uidsToDelete = await recordManager.listKeys({ + before: indexStartDt, + limit: cleanupBatchSize }); - } - async format(input) { - if (this.prompt instanceof BaseStringPromptTemplate) { - const text = await this.prompt.format(input); - return this.createMessage(text); - } else { - const content = []; - for (const prompt of this.prompt) { - let inputs = {}; - if (!("inputVariables" in prompt)) throw new Error(`Prompt ${prompt} does not have inputVariables defined.`); - for (const item of prompt.inputVariables) { - if (!inputs) inputs = { [item]: input[item] }; - inputs = { - ...inputs, - [item]: input[item] - }; - } - if (prompt instanceof BaseStringPromptTemplate) { - const formatted = await prompt.format(inputs); - let additionalContentFields; - if ("additionalContentFields" in prompt) additionalContentFields = prompt.additionalContentFields; - if (formatted !== "") content.push({ - ...additionalContentFields, - type: "text", - text: formatted - }); - } else if (prompt instanceof ImagePromptTemplate) { - const formatted = await prompt.format(inputs); - let additionalContentFields; - if ("additionalContentFields" in prompt) additionalContentFields = prompt.additionalContentFields; - content.push({ - ...additionalContentFields, - type: "image_url", - image_url: formatted - }); - } else if (prompt instanceof DictPromptTemplate) { - const formatted = await prompt.format(inputs); - let additionalContentFields; - if ("additionalContentFields" in prompt) additionalContentFields = prompt.additionalContentFields; - content.push({ - ...additionalContentFields, - ...formatted - }); - } - } - return this.createMessage(content); + while (uidsToDelete.length > 0) { + await vectorStore.delete({ ids: uidsToDelete }); + await recordManager.deleteKeys(uidsToDelete); + numDeleted += uidsToDelete.length; + uidsToDelete = await recordManager.listKeys({ + before: indexStartDt, + limit: cleanupBatchSize + }); } } - async formatMessages(values) { - return [await this.format(values)]; + return { + numAdded, + numDeleted, + numUpdated, + numSkipped + }; +} + +//#endregion + +//# sourceMappingURL=base.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/indexing/index.js + + + + +//#region src/indexing/index.ts +var indexing_exports = {}; +__export(indexing_exports, { + RecordManager: () => RecordManager, + UUIDV5_NAMESPACE: () => UUIDV5_NAMESPACE, + _HashedDocument: () => _HashedDocument, + _batch: () => _batch, + _deduplicateInOrder: () => _deduplicateInOrder, + _getSourceIdAssigner: () => _getSourceIdAssigner, + _isBaseDocumentLoader: () => _isBaseDocumentLoader, + index: () => index +}); + +//#endregion + +//# sourceMappingURL=index.js.map +// EXTERNAL MODULE: ./node_modules/base64-js/index.js +var base64_js = __nccwpck_require__(8793); +;// CONCATENATED MODULE: ./node_modules/js-tiktoken/dist/chunk-VL2OQCWN.js + + +var chunk_VL2OQCWN_defProp = Object.defineProperty; +var __defNormalProp = (obj, key, value) => key in obj ? chunk_VL2OQCWN_defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; + +// src/utils.ts +function never(_) { +} +function bytePairMerge(piece, ranks) { + let parts = Array.from( + { length: piece.length }, + (_, i) => ({ start: i, end: i + 1 }) + ); + while (parts.length > 1) { + let minRank = null; + for (let i = 0; i < parts.length - 1; i++) { + const slice = piece.slice(parts[i].start, parts[i + 1].end); + const rank = ranks.get(slice.join(",")); + if (rank == null) + continue; + if (minRank == null || rank < minRank[0]) { + minRank = [rank, i]; + } + } + if (minRank != null) { + const i = minRank[1]; + parts[i] = { start: parts[i].start, end: parts[i + 1].end }; + parts.splice(i + 1, 1); + } else { + break; + } + } + return parts; +} +function bytePairEncode(piece, ranks) { + if (piece.length === 1) + return [ranks.get(piece.join(","))]; + return bytePairMerge(piece, ranks).map((p) => ranks.get(piece.slice(p.start, p.end).join(","))).filter((x) => x != null); +} +function chunk_VL2OQCWN_escapeRegex(str) { + return str.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&"); +} +var _Tiktoken = class { + /** @internal */ + specialTokens; + /** @internal */ + inverseSpecialTokens; + /** @internal */ + patStr; + /** @internal */ + textEncoder = new TextEncoder(); + /** @internal */ + textDecoder = new TextDecoder("utf-8"); + /** @internal */ + rankMap = /* @__PURE__ */ new Map(); + /** @internal */ + textMap = /* @__PURE__ */ new Map(); + constructor(ranks, extendedSpecialTokens) { + this.patStr = ranks.pat_str; + const uncompressed = ranks.bpe_ranks.split("\n").filter(Boolean).reduce((memo, x) => { + const [_, offsetStr, ...tokens] = x.split(" "); + const offset = Number.parseInt(offsetStr, 10); + tokens.forEach((token, i) => memo[token] = offset + i); + return memo; + }, {}); + for (const [token, rank] of Object.entries(uncompressed)) { + const bytes = base64_js.toByteArray(token); + this.rankMap.set(bytes.join(","), rank); + this.textMap.set(rank, bytes); + } + this.specialTokens = { ...ranks.special_tokens, ...extendedSpecialTokens }; + this.inverseSpecialTokens = Object.entries(this.specialTokens).reduce((memo, [text, rank]) => { + memo[rank] = this.textEncoder.encode(text); + return memo; + }, {}); + } + encode(text, allowedSpecial = [], disallowedSpecial = "all") { + const regexes = new RegExp(this.patStr, "ug"); + const specialRegex = _Tiktoken.specialTokenRegex( + Object.keys(this.specialTokens) + ); + const ret = []; + const allowedSpecialSet = new Set( + allowedSpecial === "all" ? Object.keys(this.specialTokens) : allowedSpecial + ); + const disallowedSpecialSet = new Set( + disallowedSpecial === "all" ? Object.keys(this.specialTokens).filter( + (x) => !allowedSpecialSet.has(x) + ) : disallowedSpecial + ); + if (disallowedSpecialSet.size > 0) { + const disallowedSpecialRegex = _Tiktoken.specialTokenRegex([ + ...disallowedSpecialSet + ]); + const specialMatch = text.match(disallowedSpecialRegex); + if (specialMatch != null) { + throw new Error( + `The text contains a special token that is not allowed: ${specialMatch[0]}` + ); + } + } + let start = 0; + while (true) { + let nextSpecial = null; + let startFind = start; + while (true) { + specialRegex.lastIndex = startFind; + nextSpecial = specialRegex.exec(text); + if (nextSpecial == null || allowedSpecialSet.has(nextSpecial[0])) + break; + startFind = nextSpecial.index + 1; + } + const end = nextSpecial?.index ?? text.length; + for (const match of text.substring(start, end).matchAll(regexes)) { + const piece = this.textEncoder.encode(match[0]); + const token2 = this.rankMap.get(piece.join(",")); + if (token2 != null) { + ret.push(token2); + continue; + } + ret.push(...bytePairEncode(piece, this.rankMap)); + } + if (nextSpecial == null) + break; + let token = this.specialTokens[nextSpecial[0]]; + ret.push(token); + start = nextSpecial.index + nextSpecial[0].length; + } + return ret; + } + decode(tokens) { + const res = []; + let length = 0; + for (let i2 = 0; i2 < tokens.length; ++i2) { + const token = tokens[i2]; + const bytes = this.textMap.get(token) ?? this.inverseSpecialTokens[token]; + if (bytes != null) { + res.push(bytes); + length += bytes.length; + } + } + const mergedArray = new Uint8Array(length); + let i = 0; + for (const bytes of res) { + mergedArray.set(bytes, i); + i += bytes.length; + } + return this.textDecoder.decode(mergedArray); + } +}; +var Tiktoken = _Tiktoken; +__publicField(Tiktoken, "specialTokenRegex", (tokens) => { + return new RegExp(tokens.map((i) => chunk_VL2OQCWN_escapeRegex(i)).join("|"), "g"); +}); +function getEncodingNameForModel(model) { + switch (model) { + case "gpt2": { + return "gpt2"; + } + case "code-cushman-001": + case "code-cushman-002": + case "code-davinci-001": + case "code-davinci-002": + case "cushman-codex": + case "davinci-codex": + case "davinci-002": + case "text-davinci-002": + case "text-davinci-003": { + return "p50k_base"; + } + case "code-davinci-edit-001": + case "text-davinci-edit-001": { + return "p50k_edit"; + } + case "ada": + case "babbage": + case "babbage-002": + case "code-search-ada-code-001": + case "code-search-babbage-code-001": + case "curie": + case "davinci": + case "text-ada-001": + case "text-babbage-001": + case "text-curie-001": + case "text-davinci-001": + case "text-search-ada-doc-001": + case "text-search-babbage-doc-001": + case "text-search-curie-doc-001": + case "text-search-davinci-doc-001": + case "text-similarity-ada-001": + case "text-similarity-babbage-001": + case "text-similarity-curie-001": + case "text-similarity-davinci-001": { + return "r50k_base"; + } + case "gpt-3.5-turbo-instruct-0914": + case "gpt-3.5-turbo-instruct": + case "gpt-3.5-turbo-16k-0613": + case "gpt-3.5-turbo-16k": + case "gpt-3.5-turbo-0613": + case "gpt-3.5-turbo-0301": + case "gpt-3.5-turbo": + case "gpt-4-32k-0613": + case "gpt-4-32k-0314": + case "gpt-4-32k": + case "gpt-4-0613": + case "gpt-4-0314": + case "gpt-4": + case "gpt-3.5-turbo-1106": + case "gpt-35-turbo": + case "gpt-4-1106-preview": + case "gpt-4-vision-preview": + case "gpt-3.5-turbo-0125": + case "gpt-4-turbo": + case "gpt-4-turbo-2024-04-09": + case "gpt-4-turbo-preview": + case "gpt-4-0125-preview": + case "text-embedding-ada-002": + case "text-embedding-3-small": + case "text-embedding-3-large": { + return "cl100k_base"; + } + case "gpt-4o": + case "gpt-4o-2024-05-13": + case "gpt-4o-2024-08-06": + case "gpt-4o-2024-11-20": + case "gpt-4o-mini-2024-07-18": + case "gpt-4o-mini": + case "gpt-4o-search-preview": + case "gpt-4o-search-preview-2025-03-11": + case "gpt-4o-mini-search-preview": + case "gpt-4o-mini-search-preview-2025-03-11": + case "gpt-4o-audio-preview": + case "gpt-4o-audio-preview-2024-12-17": + case "gpt-4o-audio-preview-2024-10-01": + case "gpt-4o-mini-audio-preview": + case "gpt-4o-mini-audio-preview-2024-12-17": + case "o1": + case "o1-2024-12-17": + case "o1-mini": + case "o1-mini-2024-09-12": + case "o1-preview": + case "o1-preview-2024-09-12": + case "o1-pro": + case "o1-pro-2025-03-19": + case "o3": + case "o3-2025-04-16": + case "o3-mini": + case "o3-mini-2025-01-31": + case "o4-mini": + case "o4-mini-2025-04-16": + case "chatgpt-4o-latest": + case "gpt-4o-realtime": + case "gpt-4o-realtime-preview-2024-10-01": + case "gpt-4o-realtime-preview-2024-12-17": + case "gpt-4o-mini-realtime-preview": + case "gpt-4o-mini-realtime-preview-2024-12-17": + case "gpt-4.1": + case "gpt-4.1-2025-04-14": + case "gpt-4.1-mini": + case "gpt-4.1-mini-2025-04-14": + case "gpt-4.1-nano": + case "gpt-4.1-nano-2025-04-14": + case "gpt-4.5-preview": + case "gpt-4.5-preview-2025-02-27": + case "gpt-5": + case "gpt-5-2025-08-07": + case "gpt-5-nano": + case "gpt-5-nano-2025-08-07": + case "gpt-5-mini": + case "gpt-5-mini-2025-08-07": + case "gpt-5-chat-latest": { + return "o200k_base"; + } + default: + throw new Error("Unknown model"); + } +} + + + +;// CONCATENATED MODULE: ./node_modules/js-tiktoken/dist/lite.js + + +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/tiktoken.js + + + + +//#region src/utils/tiktoken.ts +var tiktoken_exports = {}; +__export(tiktoken_exports, { + encodingForModel: () => encodingForModel, + getEncoding: () => getEncoding +}); +const cache = {}; +const caller = /* @__PURE__ */ new async_caller_AsyncCaller({}); +async function getEncoding(encoding) { + if (!(encoding in cache)) cache[encoding] = caller.fetch(`https://tiktoken.pages.dev/js/${encoding}.json`).then((res) => res.json()).then((data) => new Tiktoken(data)).catch((e) => { + delete cache[encoding]; + throw e; + }); + return await cache[encoding]; +} +async function encodingForModel(model) { + return getEncoding(getEncodingNameForModel(model)); +} + +//#endregion + +//# sourceMappingURL=tiktoken.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/base.js + + + + + + + + +//#region src/language_models/base.ts +var language_models_base_base_exports = {}; +__export(language_models_base_base_exports, { + BaseLangChain: () => BaseLangChain, + BaseLanguageModel: () => BaseLanguageModel, + calculateMaxTokens: () => calculateMaxTokens, + getEmbeddingContextSize: () => getEmbeddingContextSize, + getModelContextSize: () => getModelContextSize, + getModelNameForTiktoken: () => getModelNameForTiktoken, + isOpenAITool: () => isOpenAITool +}); +const getModelNameForTiktoken = (modelName) => { + if (modelName.startsWith("gpt-5")) return "gpt-5"; + if (modelName.startsWith("gpt-3.5-turbo-16k")) return "gpt-3.5-turbo-16k"; + if (modelName.startsWith("gpt-3.5-turbo-")) return "gpt-3.5-turbo"; + if (modelName.startsWith("gpt-4-32k")) return "gpt-4-32k"; + if (modelName.startsWith("gpt-4-")) return "gpt-4"; + if (modelName.startsWith("gpt-4o")) return "gpt-4o"; + return modelName; +}; +const getEmbeddingContextSize = (modelName) => { + switch (modelName) { + case "text-embedding-ada-002": return 8191; + default: return 2046; } }; /** -* Class that represents a human message prompt template. It extends the -* BaseMessageStringPromptTemplate. -* @example -* ```typescript -* const message = HumanMessagePromptTemplate.fromTemplate("{text}"); -* const formatted = await message.format({ text: "Hello world!" }); +* Get the context window size (max input tokens) for a given model. * -* const chatPrompt = ChatPromptTemplate.fromMessages([message]); -* const formattedChatPrompt = await chatPrompt.invoke({ -* text: "Hello world!", -* }); -* ``` +* Context window sizes are sourced from official model documentation: +* - OpenAI: https://platform.openai.com/docs/models +* - Anthropic: https://docs.anthropic.com/claude/docs/models-overview +* - Google: https://ai.google.dev/gemini/docs/models/gemini +* +* @param modelName - The name of the model +* @returns The context window size in tokens */ -var HumanMessagePromptTemplate = class extends _StringImageMessagePromptTemplate { - static _messageClass() { - return HumanMessage; +const getModelContextSize = (modelName) => { + const normalizedName = getModelNameForTiktoken(modelName); + switch (normalizedName) { + case "gpt-5": + case "gpt-5-turbo": + case "gpt-5-turbo-preview": return 4e5; + case "gpt-4o": + case "gpt-4o-mini": + case "gpt-4o-2024-05-13": + case "gpt-4o-2024-08-06": return 128e3; + case "gpt-4-turbo": + case "gpt-4-turbo-preview": + case "gpt-4-turbo-2024-04-09": + case "gpt-4-0125-preview": + case "gpt-4-1106-preview": return 128e3; + case "gpt-4-32k": + case "gpt-4-32k-0314": + case "gpt-4-32k-0613": return 32768; + case "gpt-4": + case "gpt-4-0314": + case "gpt-4-0613": return 8192; + case "gpt-3.5-turbo-16k": + case "gpt-3.5-turbo-16k-0613": return 16384; + case "gpt-3.5-turbo": + case "gpt-3.5-turbo-0301": + case "gpt-3.5-turbo-0613": + case "gpt-3.5-turbo-1106": + case "gpt-3.5-turbo-0125": return 4096; + case "text-davinci-003": + case "text-davinci-002": return 4097; + case "text-davinci-001": return 2049; + case "text-curie-001": + case "text-babbage-001": + case "text-ada-001": return 2048; + case "code-davinci-002": + case "code-davinci-001": return 8e3; + case "code-cushman-001": return 2048; + case "claude-3-5-sonnet-20241022": + case "claude-3-5-sonnet-20240620": + case "claude-3-opus-20240229": + case "claude-3-sonnet-20240229": + case "claude-3-haiku-20240307": + case "claude-2.1": return 2e5; + case "claude-2.0": + case "claude-instant-1.2": return 1e5; + case "gemini-1.5-pro": + case "gemini-1.5-pro-latest": + case "gemini-1.5-flash": + case "gemini-1.5-flash-latest": return 1e6; + case "gemini-pro": + case "gemini-pro-vision": return 32768; + default: return 4097; } - static lc_name() { - return "HumanMessagePromptTemplate"; +}; +/** +* Whether or not the input matches the OpenAI tool definition. +* @param {unknown} tool The input to check. +* @returns {boolean} Whether the input is an OpenAI tool definition. +*/ +function isOpenAITool(tool) { + if (typeof tool !== "object" || !tool) return false; + if ("type" in tool && tool.type === "function" && "function" in tool && typeof tool.function === "object" && tool.function && "name" in tool.function && "parameters" in tool.function) return true; + return false; +} +const calculateMaxTokens = async ({ prompt, modelName }) => { + let numTokens; + try { + numTokens = (await encodingForModel(getModelNameForTiktoken(modelName))).encode(prompt).length; + } catch { + console.warn("Failed to calculate number of tokens, falling back to approximate count"); + numTokens = Math.ceil(prompt.length / 4); } + const maxTokens = getModelContextSize(modelName); + return maxTokens - numTokens; }; +const getVerbosity = () => false; /** -* Class that represents an AI message prompt template. It extends the -* BaseMessageStringPromptTemplate. +* Base class for language models, chains, tools. */ -var AIMessagePromptTemplate = class extends _StringImageMessagePromptTemplate { - static _messageClass() { - return AIMessage; +var BaseLangChain = class extends Runnable { + /** + * Whether to print out response text. + */ + verbose; + callbacks; + tags; + metadata; + get lc_attributes() { + return { + callbacks: void 0, + verbose: void 0 + }; } - static lc_name() { - return "AIMessagePromptTemplate"; + constructor(params) { + super(params); + this.verbose = params.verbose ?? getVerbosity(); + this.callbacks = params.callbacks; + this.tags = params.tags ?? []; + this.metadata = params.metadata ?? {}; } }; /** -* Class that represents a system message prompt template. It extends the -* BaseMessageStringPromptTemplate. -* @example -* ```typescript -* const message = SystemMessagePromptTemplate.fromTemplate("{text}"); -* const formatted = await message.format({ text: "Hello world!" }); -* -* const chatPrompt = ChatPromptTemplate.fromMessages([message]); -* const formattedChatPrompt = await chatPrompt.invoke({ -* text: "Hello world!", -* }); -* ``` +* Base class for language models. */ -var SystemMessagePromptTemplate = class extends _StringImageMessagePromptTemplate { - static _messageClass() { - return SystemMessage; +var BaseLanguageModel = class extends BaseLangChain { + /** + * Keys that the language model accepts as call options. + */ + get callKeys() { + return [ + "stop", + "timeout", + "signal", + "tags", + "metadata", + "callbacks" + ]; } - static lc_name() { - return "SystemMessagePromptTemplate"; + /** + * The async caller should be used by subclasses to make any async calls, + * which will thus benefit from the concurrency and retry logic. + */ + caller; + cache; + constructor({ callbacks, callbackManager,...params }) { + const { cache,...rest } = params; + super({ + callbacks: callbacks ?? callbackManager, + ...rest + }); + if (typeof cache === "object") this.cache = cache; + else if (cache) this.cache = InMemoryCache.global(); + else this.cache = void 0; + this.caller = new async_caller_AsyncCaller(params ?? {}); } -}; -function _isBaseMessagePromptTemplate(baseMessagePromptTemplateLike) { - return typeof baseMessagePromptTemplateLike.formatMessages === "function"; -} -function _coerceMessagePromptTemplateLike(messagePromptTemplateLike, extra) { - if (_isBaseMessagePromptTemplate(messagePromptTemplateLike) || isBaseMessage(messagePromptTemplateLike)) return messagePromptTemplateLike; - if (Array.isArray(messagePromptTemplateLike) && messagePromptTemplateLike[0] === "placeholder") { - const messageContent = messagePromptTemplateLike[1]; - if (extra?.templateFormat === "mustache" && typeof messageContent === "string" && messageContent.slice(0, 2) === "{{" && messageContent.slice(-2) === "}}") { - const variableName = messageContent.slice(2, -2); - return new MessagesPlaceholder({ - variableName, - optional: true - }); - } else if (typeof messageContent === "string" && messageContent[0] === "{" && messageContent[messageContent.length - 1] === "}") { - const variableName = messageContent.slice(1, -1); - return new MessagesPlaceholder({ - variableName, - optional: true - }); + _encoding; + /** + * Get the number of tokens in the content. + * @param content The content to get the number of tokens for. + * @returns The number of tokens in the content. + */ + async getNumTokens(content) { + let textContent; + if (typeof content === "string") textContent = content; + else + /** + * Content is an array of ContentBlock + * + * ToDo(@christian-bromann): This is a temporary fix to get the number of tokens for the content. + * We need to find a better way to do this. + * @see https://github.com/langchain-ai/langchainjs/pull/8341#pullrequestreview-2933713116 + */ + textContent = content.map((item) => { + if (typeof item === "string") return item; + if (item.type === "text" && "text" in item) return item.text; + return ""; + }).join(""); + let numTokens = Math.ceil(textContent.length / 4); + if (!this._encoding) try { + this._encoding = await encodingForModel("modelName" in this ? getModelNameForTiktoken(this.modelName) : "gpt2"); + } catch (error) { + console.warn("Failed to calculate number of tokens, falling back to approximate count", error); } - throw new Error(`Invalid placeholder template for format ${extra?.templateFormat ?? `"f-string"`}: "${messagePromptTemplateLike[1]}". Expected a variable name surrounded by ${extra?.templateFormat === "mustache" ? "double" : "single"} curly braces.`); + if (this._encoding) try { + numTokens = this._encoding.encode(textContent).length; + } catch (error) { + console.warn("Failed to calculate number of tokens, falling back to approximate count", error); + } + return numTokens; } - const message = utils_coerceMessageLikeToMessage(messagePromptTemplateLike); - let templateData; - if (typeof message.content === "string") templateData = message.content; - else templateData = message.content.map((item) => { - if ("text" in item) return { - ...item, - text: item.text + static _convertInputToPromptValue(input) { + if (typeof input === "string") return new StringPromptValue(input); + else if (Array.isArray(input)) return new ChatPromptValue(input.map(utils_coerceMessageLikeToMessage)); + else return input; + } + /** + * Get the identifying parameters of the LLM. + */ + _identifyingParams() { + return {}; + } + /** + * Create a unique cache key for a specific call to a specific language model. + * @param callOptions Call options for the model + * @returns A unique cache key. + */ + _getSerializedCacheKeyParametersForCall({ config,...callOptions }) { + const params = { + ...this._identifyingParams(), + ...callOptions, + _type: this._llmType(), + _model: this._modelType() }; - else if ("image_url" in item) return { - ...item, - image_url: item.image_url + const filteredEntries = Object.entries(params).filter(([_, value]) => value !== void 0); + const serializedEntries = filteredEntries.map(([key, value]) => `${key}:${JSON.stringify(value)}`).sort().join(","); + return serializedEntries; + } + /** + * @deprecated + * Return a json-like object representing this LLM. + */ + serialize() { + return { + ...this._identifyingParams(), + _type: this._llmType(), + _model: this._modelType() }; - else return item; - }); - if (message._getType() === "human") return HumanMessagePromptTemplate.fromTemplate(templateData, extra); - else if (message._getType() === "ai") return AIMessagePromptTemplate.fromTemplate(templateData, extra); - else if (message._getType() === "system") return SystemMessagePromptTemplate.fromTemplate(templateData, extra); - else if (ChatMessage.isInstance(message)) return ChatMessagePromptTemplate.fromTemplate(message.content, message.role, extra); - else throw new Error(`Could not coerce message prompt template from input. Received message type: "${message._getType()}".`); -} -function isMessagesPlaceholder(x) { - return x.constructor.lc_name() === "MessagesPlaceholder"; -} + } + /** + * @deprecated + * Load an LLM from a json-like object describing it. + */ + static async deserialize(_data) { + throw new Error("Use .toJSON() instead"); + } + /** + * Return profiling information for the model. + * + * @returns {ModelProfile} An object describing the model's capabilities and constraints + */ + get profile() { + return {}; + } +}; + +//#endregion + +//# sourceMappingURL=base.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/passthrough.js + + + + +//#region src/runnables/passthrough.ts /** -* Class that represents a chat prompt. It extends the -* BaseChatPromptTemplate and uses an array of BaseMessagePromptTemplate -* instances to format a series of messages for a conversation. +* A runnable to passthrough inputs unchanged or with additional keys. +* +* This runnable behaves almost like the identity function, except that it +* can be configured to add additional keys to the output, if the input is +* an object. +* +* The example below demonstrates how to use `RunnablePassthrough to +* passthrough the input from the `.invoke()` +* * @example * ```typescript -* const message = SystemMessagePromptTemplate.fromTemplate("{text}"); -* const chatPrompt = ChatPromptTemplate.fromMessages([ -* ["ai", "You are a helpful assistant."], -* message, +* const chain = RunnableSequence.from([ +* { +* question: new RunnablePassthrough(), +* context: async () => loadContextFromStore(), +* }, +* prompt, +* llm, +* outputParser, * ]); -* const formattedChatPrompt = await chatPrompt.invoke({ -* text: "Hello world!", -* }); +* const response = await chain.invoke( +* "I can pass a single string instead of an object since I'm using `RunnablePassthrough`." +* ); * ``` */ -var ChatPromptTemplate = class ChatPromptTemplate extends BaseChatPromptTemplate { +var RunnablePassthrough = class extends Runnable { static lc_name() { - return "ChatPromptTemplate"; - } - get lc_aliases() { - return { promptMessages: "messages" }; - } - promptMessages; - validateTemplate = true; - templateFormat = "f-string"; - constructor(input) { - super(input); - if (input.templateFormat === "mustache" && input.validateTemplate === void 0) this.validateTemplate = false; - Object.assign(this, input); - if (this.validateTemplate) { - const inputVariablesMessages = /* @__PURE__ */ new Set(); - for (const promptMessage of this.promptMessages) { - if (promptMessage instanceof BaseMessage) continue; - for (const inputVariable of promptMessage.inputVariables) inputVariablesMessages.add(inputVariable); - } - const totalInputVariables = this.inputVariables; - const inputVariablesInstance = new Set(this.partialVariables ? totalInputVariables.concat(Object.keys(this.partialVariables)) : totalInputVariables); - const difference = new Set([...inputVariablesInstance].filter((x) => !inputVariablesMessages.has(x))); - if (difference.size > 0) throw new Error(`Input variables \`${[...difference]}\` are not used in any of the prompt messages.`); - const otherDifference = new Set([...inputVariablesMessages].filter((x) => !inputVariablesInstance.has(x))); - if (otherDifference.size > 0) throw new Error(`Input variables \`${[...otherDifference]}\` are used in prompt messages but not in the prompt template.`); - } - } - _getPromptType() { - return "chat"; - } - async _parseImagePrompts(message, inputValues) { - if (typeof message.content === "string") return message; - const formattedMessageContent = await Promise.all(message.content.map(async (item) => { - if (item.type !== "image_url") return item; - let imageUrl = ""; - if (typeof item.image_url === "string") imageUrl = item.image_url; - else if (typeof item.image_url === "object" && item.image_url !== null && "url" in item.image_url && typeof item.image_url.url === "string") imageUrl = item.image_url.url; - const promptTemplatePlaceholder = PromptTemplate.fromTemplate(imageUrl, { templateFormat: this.templateFormat }); - const formattedUrl = await promptTemplatePlaceholder.format(inputValues); - if (typeof item.image_url === "object" && item.image_url !== null && "url" in item.image_url) item.image_url.url = formattedUrl; - else item.image_url = formattedUrl; - return item; - })); - message.content = formattedMessageContent; - return message; - } - async formatMessages(values) { - const allValues = await this.mergePartialAndUserVariables(values); - let resultMessages = []; - for (const promptMessage of this.promptMessages) if (promptMessage instanceof BaseMessage) resultMessages.push(await this._parseImagePrompts(promptMessage, allValues)); - else { - let inputValues; - if (this.templateFormat === "mustache") inputValues = { ...allValues }; - else inputValues = promptMessage.inputVariables.reduce((acc, inputVariable) => { - if (!(inputVariable in allValues) && !(isMessagesPlaceholder(promptMessage) && promptMessage.optional)) { - const error = addLangChainErrorFields(/* @__PURE__ */ new Error(`Missing value for input variable \`${inputVariable.toString()}\``), "INVALID_PROMPT_INPUT"); - throw error; - } - acc[inputVariable] = allValues[inputVariable]; - return acc; - }, {}); - const message = await promptMessage.formatMessages(inputValues); - resultMessages = resultMessages.concat(message); - } - return resultMessages; + return "RunnablePassthrough"; } - async partial(values) { - const newInputVariables = this.inputVariables.filter((iv) => !(iv in values)); - const newPartialVariables = { - ...this.partialVariables ?? {}, - ...values - }; - const promptDict = { - ...this, - inputVariables: newInputVariables, - partialVariables: newPartialVariables - }; - return new ChatPromptTemplate(promptDict); + lc_namespace = ["langchain_core", "runnables"]; + lc_serializable = true; + func; + constructor(fields) { + super(fields); + if (fields) this.func = fields.func; } - static fromTemplate(template, options) { - const prompt = PromptTemplate.fromTemplate(template, options); - const humanTemplate = new HumanMessagePromptTemplate({ prompt }); - return this.fromMessages([humanTemplate]); + async invoke(input, options) { + const config = ensureConfig(options); + if (this.func) await this.func(input, config); + return this._callWithConfig((input$1) => Promise.resolve(input$1), input, config); } - /** - * Create a chat model-specific prompt from individual chat messages - * or message-like tuples. - * @param promptMessages Messages to be passed to the chat model - * @returns A new ChatPromptTemplate - */ - static fromMessages(promptMessages, extra) { - const flattenedMessages = promptMessages.reduce((acc, promptMessage) => acc.concat(promptMessage instanceof ChatPromptTemplate ? promptMessage.promptMessages : [_coerceMessagePromptTemplateLike(promptMessage, extra)]), []); - const flattenedPartialVariables = promptMessages.reduce((acc, promptMessage) => promptMessage instanceof ChatPromptTemplate ? Object.assign(acc, promptMessage.partialVariables) : acc, Object.create(null)); - const inputVariables = /* @__PURE__ */ new Set(); - for (const promptMessage of flattenedMessages) { - if (promptMessage instanceof BaseMessage) continue; - for (const inputVariable of promptMessage.inputVariables) { - if (inputVariable in flattenedPartialVariables) continue; - inputVariables.add(inputVariable); + async *transform(generator, options) { + const config = ensureConfig(options); + let finalOutput; + let finalOutputSupported = true; + for await (const chunk of this._transformStreamWithConfig(generator, (input) => input, config)) { + yield chunk; + if (finalOutputSupported) if (finalOutput === void 0) finalOutput = chunk; + else try { + finalOutput = concat(finalOutput, chunk); + } catch { + finalOutput = void 0; + finalOutputSupported = false; } } - return new this({ - ...extra, - inputVariables: [...inputVariables], - promptMessages: flattenedMessages, - partialVariables: flattenedPartialVariables, - templateFormat: extra?.templateFormat - }); + if (this.func && finalOutput !== void 0) await this.func(finalOutput, config); + } + /** + * A runnable that assigns key-value pairs to the input. + * + * The example below shows how you could use it with an inline function. + * + * @example + * ```typescript + * const prompt = + * PromptTemplate.fromTemplate(`Write a SQL query to answer the question using the following schema: {schema} + * Question: {question} + * SQL Query:`); + * + * // The `RunnablePassthrough.assign()` is used here to passthrough the input from the `.invoke()` + * // call (in this example it's the question), along with any inputs passed to the `.assign()` method. + * // In this case, we're passing the schema. + * const sqlQueryGeneratorChain = RunnableSequence.from([ + * RunnablePassthrough.assign({ + * schema: async () => db.getTableInfo(), + * }), + * prompt, + * new ChatOpenAI({ model: "gpt-4o-mini" }).withConfig({ stop: ["\nSQLResult:"] }), + * new StringOutputParser(), + * ]); + * const result = await sqlQueryGeneratorChain.invoke({ + * question: "How many employees are there?", + * }); + * ``` + */ + static assign(mapping) { + return new RunnableAssign(new RunnableMap({ steps: mapping })); } }; //#endregion -//# sourceMappingURL=chat.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/few_shot.js +//# sourceMappingURL=passthrough.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/utils.js +//#region src/language_models/utils.ts +const language_models_utils_iife = (fn) => fn(); +function castStandardMessageContent(message) { + const Cls = message.constructor; + return new Cls({ + ...message, + content: message.contentBlocks, + response_metadata: { + ...message.response_metadata, + output_version: "v1" + } + }); +} + +//#endregion +//# sourceMappingURL=utils.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/chat_models.js -//#region src/prompts/few_shot.ts -/** -* Prompt template that contains few-shot examples. -* @augments BasePromptTemplate -* @augments FewShotPromptTemplateInput -* @example -* ```typescript -* const examplePrompt = PromptTemplate.fromTemplate( -* "Input: {input}\nOutput: {output}", -* ); -* -* const exampleSelector = await SemanticSimilarityExampleSelector.fromExamples( -* [ -* { input: "happy", output: "sad" }, -* { input: "tall", output: "short" }, -* { input: "energetic", output: "lethargic" }, -* { input: "sunny", output: "gloomy" }, -* { input: "windy", output: "calm" }, -* ], -* new OpenAIEmbeddings(), -* HNSWLib, -* { k: 1 }, -* ); -* -* const dynamicPrompt = new FewShotPromptTemplate({ -* exampleSelector, -* examplePrompt, -* prefix: "Give the antonym of every input", -* suffix: "Input: {adjective}\nOutput:", -* inputVariables: ["adjective"], -* }); -* -* // Format the dynamic prompt with the input 'rainy' -* console.log(await dynamicPrompt.format({ adjective: "rainy" })); -* -* ``` -*/ -var FewShotPromptTemplate = class FewShotPromptTemplate extends BaseStringPromptTemplate { - lc_serializable = false; - examples; - exampleSelector; - examplePrompt; - suffix = ""; - exampleSeparator = "\n\n"; - prefix = ""; - templateFormat = "f-string"; - validateTemplate = true; - constructor(input) { - super(input); - Object.assign(this, input); - if (this.examples !== void 0 && this.exampleSelector !== void 0) throw new Error("Only one of 'examples' and 'example_selector' should be provided"); - if (this.examples === void 0 && this.exampleSelector === void 0) throw new Error("One of 'examples' and 'example_selector' should be provided"); - if (this.validateTemplate) { - let totalInputVariables = this.inputVariables; - if (this.partialVariables) totalInputVariables = totalInputVariables.concat(Object.keys(this.partialVariables)); - checkValidTemplate(this.prefix + this.suffix, this.templateFormat, totalInputVariables); + + + + + + + + + + + + + + +//#region src/language_models/chat_models.ts +var chat_models_exports = {}; +__export(chat_models_exports, { + BaseChatModel: () => BaseChatModel, + SimpleChatModel: () => SimpleChatModel +}); +function _formatForTracing(messages) { + const messagesToTrace = []; + for (const message of messages) { + let messageToTrace = message; + if (Array.isArray(message.content)) for (let idx = 0; idx < message.content.length; idx++) { + const block = message.content[idx]; + if (isURLContentBlock(block) || isBase64ContentBlock(block)) { + if (messageToTrace === message) messageToTrace = new message.constructor({ + ...messageToTrace, + content: [ + ...message.content.slice(0, idx), + convertToOpenAIImageBlock(block), + ...message.content.slice(idx + 1) + ] + }); + } } + messagesToTrace.push(messageToTrace); } - _getPromptType() { - return "few_shot"; - } - static lc_name() { - return "FewShotPromptTemplate"; + return messagesToTrace; +} +/** +* Base class for chat models. It extends the BaseLanguageModel class and +* provides methods for generating chat based on input messages. +*/ +var BaseChatModel = class BaseChatModel extends BaseLanguageModel { + lc_namespace = [ + "langchain", + "chat_models", + this._llmType() + ]; + disableStreaming = false; + outputVersion; + get callKeys() { + return [...super.callKeys, "outputVersion"]; } - async getExamples(inputVariables) { - if (this.examples !== void 0) return this.examples; - if (this.exampleSelector !== void 0) return this.exampleSelector.selectExamples(inputVariables); - throw new Error("One of 'examples' and 'example_selector' should be provided"); + constructor(fields) { + super(fields); + this.outputVersion = language_models_utils_iife(() => { + const outputVersion = fields.outputVersion ?? getEnvironmentVariable("LC_OUTPUT_VERSION"); + if (outputVersion && ["v0", "v1"].includes(outputVersion)) return outputVersion; + return "v0"; + }); } - async partial(values) { - const newInputVariables = this.inputVariables.filter((iv) => !(iv in values)); - const newPartialVariables = { - ...this.partialVariables ?? {}, - ...values - }; - const promptDict = { - ...this, - inputVariables: newInputVariables, - partialVariables: newPartialVariables - }; - return new FewShotPromptTemplate(promptDict); + _separateRunnableConfigFromCallOptionsCompat(options) { + const [runnableConfig, callOptions] = super._separateRunnableConfigFromCallOptions(options); + callOptions.signal = runnableConfig.signal; + return [runnableConfig, callOptions]; } /** - * Formats the prompt with the given values. - * @param values The values to format the prompt with. - * @returns A promise that resolves to a string representing the formatted prompt. + * Invokes the chat model with a single input. + * @param input The input for the language model. + * @param options The call options. + * @returns A Promise that resolves to a BaseMessageChunk. */ - async format(values) { - const allValues = await this.mergePartialAndUserVariables(values); - const examples = await this.getExamples(allValues); - const exampleStrings = await Promise.all(examples.map((example) => this.examplePrompt.format(example))); - const template = [ - this.prefix, - ...exampleStrings, - this.suffix - ].join(this.exampleSeparator); - return renderTemplate(template, this.templateFormat, allValues); - } - serialize() { - if (this.exampleSelector || !this.examples) throw new Error("Serializing an example selector is not currently supported"); - if (this.outputParser !== void 0) throw new Error("Serializing an output parser is not currently supported"); - return { - _type: this._getPromptType(), - input_variables: this.inputVariables, - example_prompt: this.examplePrompt.serialize(), - example_separator: this.exampleSeparator, - suffix: this.suffix, - prefix: this.prefix, - template_format: this.templateFormat, - examples: this.examples - }; + async invoke(input, options) { + const promptValue = BaseChatModel._convertInputToPromptValue(input); + const result = await this.generatePrompt([promptValue], options, options?.callbacks); + const chatGeneration = result.generations[0][0]; + return chatGeneration.message; } - static async deserialize(data) { - const { example_prompt } = data; - if (!example_prompt) throw new Error("Missing example prompt"); - const examplePrompt = await PromptTemplate.deserialize(example_prompt); - let examples; - if (Array.isArray(data.examples)) examples = data.examples; - else throw new Error("Invalid examples format. Only list or string are supported."); - return new FewShotPromptTemplate({ - inputVariables: data.input_variables, - examplePrompt, - examples, - exampleSeparator: data.example_separator, - prefix: data.prefix, - suffix: data.suffix, - templateFormat: data.template_format - }); + async *_streamResponseChunks(_messages, _options, _runManager) { + throw new Error("Not implemented."); } -}; -/** -* Chat prompt template that contains few-shot examples. -* @augments BasePromptTemplateInput -* @augments FewShotChatMessagePromptTemplateInput -*/ -var FewShotChatMessagePromptTemplate = class FewShotChatMessagePromptTemplate extends BaseChatPromptTemplate { - lc_serializable = true; - examples; - exampleSelector; - examplePrompt; - suffix = ""; - exampleSeparator = "\n\n"; - prefix = ""; - templateFormat = "f-string"; - validateTemplate = true; - _getPromptType() { - return "few_shot_chat"; + async *_streamIterator(input, options) { + if (this._streamResponseChunks === BaseChatModel.prototype._streamResponseChunks || this.disableStreaming) yield this.invoke(input, options); + else { + const prompt = BaseChatModel._convertInputToPromptValue(input); + const messages = prompt.toChatMessages(); + const [runnableConfig, callOptions] = this._separateRunnableConfigFromCallOptionsCompat(options); + const inheritableMetadata = { + ...runnableConfig.metadata, + ...this.getLsParams(callOptions) + }; + const callbackManager_ = await CallbackManager.configure(runnableConfig.callbacks, this.callbacks, runnableConfig.tags, this.tags, inheritableMetadata, this.metadata, { verbose: this.verbose }); + const extra = { + options: callOptions, + invocation_params: this?.invocationParams(callOptions), + batch_size: 1 + }; + const outputVersion = callOptions.outputVersion ?? this.outputVersion; + const runManagers = await callbackManager_?.handleChatModelStart(this.toJSON(), [_formatForTracing(messages)], runnableConfig.runId, void 0, extra, void 0, void 0, runnableConfig.runName); + let generationChunk; + let llmOutput; + try { + for await (const chunk of this._streamResponseChunks(messages, callOptions, runManagers?.[0])) { + if (chunk.message.id == null) { + const runId = runManagers?.at(0)?.runId; + if (runId != null) chunk.message._updateId(`run-${runId}`); + } + chunk.message.response_metadata = { + ...chunk.generationInfo, + ...chunk.message.response_metadata + }; + if (outputVersion === "v1") yield castStandardMessageContent(chunk.message); + else yield chunk.message; + if (!generationChunk) generationChunk = chunk; + else generationChunk = generationChunk.concat(chunk); + if (isAIMessageChunk(chunk.message) && chunk.message.usage_metadata !== void 0) llmOutput = { tokenUsage: { + promptTokens: chunk.message.usage_metadata.input_tokens, + completionTokens: chunk.message.usage_metadata.output_tokens, + totalTokens: chunk.message.usage_metadata.total_tokens + } }; + } + } catch (err) { + await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMError(err))); + throw err; + } + await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMEnd({ + generations: [[generationChunk]], + llmOutput + }))); + } } - static lc_name() { - return "FewShotChatMessagePromptTemplate"; + getLsParams(options) { + const providerName = this.getName().startsWith("Chat") ? this.getName().replace("Chat", "") : this.getName(); + return { + ls_model_type: "chat", + ls_stop: options.stop, + ls_provider: providerName + }; } - constructor(fields) { - super(fields); - this.examples = fields.examples; - this.examplePrompt = fields.examplePrompt; - this.exampleSeparator = fields.exampleSeparator ?? "\n\n"; - this.exampleSelector = fields.exampleSelector; - this.prefix = fields.prefix ?? ""; - this.suffix = fields.suffix ?? ""; - this.templateFormat = fields.templateFormat ?? "f-string"; - this.validateTemplate = fields.validateTemplate ?? true; - if (this.examples !== void 0 && this.exampleSelector !== void 0) throw new Error("Only one of 'examples' and 'example_selector' should be provided"); - if (this.examples === void 0 && this.exampleSelector === void 0) throw new Error("One of 'examples' and 'example_selector' should be provided"); - if (this.validateTemplate) { - let totalInputVariables = this.inputVariables; - if (this.partialVariables) totalInputVariables = totalInputVariables.concat(Object.keys(this.partialVariables)); - checkValidTemplate(this.prefix + this.suffix, this.templateFormat, totalInputVariables); + /** @ignore */ + async _generateUncached(messages, parsedOptions, handledOptions, startedRunManagers) { + const baseMessages = messages.map((messageList) => messageList.map(utils_coerceMessageLikeToMessage)); + let runManagers; + if (startedRunManagers !== void 0 && startedRunManagers.length === baseMessages.length) runManagers = startedRunManagers; + else { + const inheritableMetadata = { + ...handledOptions.metadata, + ...this.getLsParams(parsedOptions) + }; + const callbackManager_ = await CallbackManager.configure(handledOptions.callbacks, this.callbacks, handledOptions.tags, this.tags, inheritableMetadata, this.metadata, { verbose: this.verbose }); + const extra = { + options: parsedOptions, + invocation_params: this?.invocationParams(parsedOptions), + batch_size: 1 + }; + runManagers = await callbackManager_?.handleChatModelStart(this.toJSON(), baseMessages.map(_formatForTracing), handledOptions.runId, void 0, extra, void 0, void 0, handledOptions.runName); + } + const outputVersion = parsedOptions.outputVersion ?? this.outputVersion; + const generations = []; + const llmOutputs = []; + const hasStreamingHandler = !!runManagers?.[0].handlers.find(callbackHandlerPrefersStreaming); + if (hasStreamingHandler && !this.disableStreaming && baseMessages.length === 1 && this._streamResponseChunks !== BaseChatModel.prototype._streamResponseChunks) try { + const stream = await this._streamResponseChunks(baseMessages[0], parsedOptions, runManagers?.[0]); + let aggregated; + let llmOutput; + for await (const chunk of stream) { + if (chunk.message.id == null) { + const runId = runManagers?.at(0)?.runId; + if (runId != null) chunk.message._updateId(`run-${runId}`); + } + if (aggregated === void 0) aggregated = chunk; + else aggregated = concat(aggregated, chunk); + if (isAIMessageChunk(chunk.message) && chunk.message.usage_metadata !== void 0) llmOutput = { tokenUsage: { + promptTokens: chunk.message.usage_metadata.input_tokens, + completionTokens: chunk.message.usage_metadata.output_tokens, + totalTokens: chunk.message.usage_metadata.total_tokens + } }; + } + if (aggregated === void 0) throw new Error("Received empty response from chat model call."); + generations.push([aggregated]); + await runManagers?.[0].handleLLMEnd({ + generations, + llmOutput + }); + } catch (e) { + await runManagers?.[0].handleLLMError(e); + throw e; + } + else { + const results = await Promise.allSettled(baseMessages.map(async (messageList, i) => { + const generateResults = await this._generate(messageList, { + ...parsedOptions, + promptIndex: i + }, runManagers?.[i]); + if (outputVersion === "v1") for (const generation of generateResults.generations) generation.message = castStandardMessageContent(generation.message); + return generateResults; + })); + await Promise.all(results.map(async (pResult, i) => { + if (pResult.status === "fulfilled") { + const result = pResult.value; + for (const generation of result.generations) { + if (generation.message.id == null) { + const runId = runManagers?.at(0)?.runId; + if (runId != null) generation.message._updateId(`run-${runId}`); + } + generation.message.response_metadata = { + ...generation.generationInfo, + ...generation.message.response_metadata + }; + } + if (result.generations.length === 1) result.generations[0].message.response_metadata = { + ...result.llmOutput, + ...result.generations[0].message.response_metadata + }; + generations[i] = result.generations; + llmOutputs[i] = result.llmOutput; + return runManagers?.[i]?.handleLLMEnd({ + generations: [result.generations], + llmOutput: result.llmOutput + }); + } else { + await runManagers?.[i]?.handleLLMError(pResult.reason); + return Promise.reject(pResult.reason); + } + })); } + const output = { + generations, + llmOutput: llmOutputs.length ? this._combineLLMOutput?.(...llmOutputs) : void 0 + }; + Object.defineProperty(output, RUN_KEY, { + value: runManagers ? { runIds: runManagers?.map((manager) => manager.runId) } : void 0, + configurable: true + }); + return output; } - async getExamples(inputVariables) { - if (this.examples !== void 0) return this.examples; - if (this.exampleSelector !== void 0) return this.exampleSelector.selectExamples(inputVariables); - throw new Error("One of 'examples' and 'example_selector' should be provided"); + async _generateCached({ messages, cache, llmStringKey, parsedOptions, handledOptions }) { + const baseMessages = messages.map((messageList) => messageList.map(utils_coerceMessageLikeToMessage)); + const inheritableMetadata = { + ...handledOptions.metadata, + ...this.getLsParams(parsedOptions) + }; + const callbackManager_ = await CallbackManager.configure(handledOptions.callbacks, this.callbacks, handledOptions.tags, this.tags, inheritableMetadata, this.metadata, { verbose: this.verbose }); + const extra = { + options: parsedOptions, + invocation_params: this?.invocationParams(parsedOptions), + batch_size: 1 + }; + const runManagers = await callbackManager_?.handleChatModelStart(this.toJSON(), baseMessages.map(_formatForTracing), handledOptions.runId, void 0, extra, void 0, void 0, handledOptions.runName); + const missingPromptIndices = []; + const results = await Promise.allSettled(baseMessages.map(async (baseMessage, index) => { + const prompt = BaseChatModel._convertInputToPromptValue(baseMessage).toString(); + const result = await cache.lookup(prompt, llmStringKey); + if (result == null) missingPromptIndices.push(index); + return result; + })); + const cachedResults = results.map((result, index) => ({ + result, + runManager: runManagers?.[index] + })).filter(({ result }) => result.status === "fulfilled" && result.value != null || result.status === "rejected"); + const outputVersion = parsedOptions.outputVersion ?? this.outputVersion; + const generations = []; + await Promise.all(cachedResults.map(async ({ result: promiseResult, runManager }, i) => { + if (promiseResult.status === "fulfilled") { + const result = promiseResult.value; + generations[i] = result.map((result$1) => { + if ("message" in result$1 && isBaseMessage(result$1.message) && isAIMessage(result$1.message)) { + result$1.message.usage_metadata = { + input_tokens: 0, + output_tokens: 0, + total_tokens: 0 + }; + if (outputVersion === "v1") result$1.message = castStandardMessageContent(result$1.message); + } + result$1.generationInfo = { + ...result$1.generationInfo, + tokenUsage: {} + }; + return result$1; + }); + if (result.length) await runManager?.handleLLMNewToken(result[0].text); + return runManager?.handleLLMEnd({ generations: [result] }, void 0, void 0, void 0, { cached: true }); + } else { + await runManager?.handleLLMError(promiseResult.reason, void 0, void 0, void 0, { cached: true }); + return Promise.reject(promiseResult.reason); + } + })); + const output = { + generations, + missingPromptIndices, + startedRunManagers: runManagers + }; + Object.defineProperty(output, RUN_KEY, { + value: runManagers ? { runIds: runManagers?.map((manager) => manager.runId) } : void 0, + configurable: true + }); + return output; } /** - * Formats the list of values and returns a list of formatted messages. - * @param values The values to format the prompt with. - * @returns A promise that resolves to a string representing the formatted prompt. + * Generates chat based on the input messages. + * @param messages An array of arrays of BaseMessage instances. + * @param options The call options or an array of stop sequences. + * @param callbacks The callbacks for the language model. + * @returns A Promise that resolves to an LLMResult. */ - async formatMessages(values) { - const allValues = await this.mergePartialAndUserVariables(values); - let examples = await this.getExamples(allValues); - examples = examples.map((example) => { - const result = {}; - this.examplePrompt.inputVariables.forEach((inputVariable) => { - result[inputVariable] = example[inputVariable]; - }); - return result; + async generate(messages, options, callbacks) { + let parsedOptions; + if (Array.isArray(options)) parsedOptions = { stop: options }; + else parsedOptions = options; + const baseMessages = messages.map((messageList) => messageList.map(utils_coerceMessageLikeToMessage)); + const [runnableConfig, callOptions] = this._separateRunnableConfigFromCallOptionsCompat(parsedOptions); + runnableConfig.callbacks = runnableConfig.callbacks ?? callbacks; + if (!this.cache) return this._generateUncached(baseMessages, callOptions, runnableConfig); + const { cache } = this; + const llmStringKey = this._getSerializedCacheKeyParametersForCall(callOptions); + const { generations, missingPromptIndices, startedRunManagers } = await this._generateCached({ + messages: baseMessages, + cache, + llmStringKey, + parsedOptions: callOptions, + handledOptions: runnableConfig }); - const messages = []; - for (const example of examples) { - const exampleMessages = await this.examplePrompt.formatMessages(example); - messages.push(...exampleMessages); + let llmOutput = {}; + if (missingPromptIndices.length > 0) { + const results = await this._generateUncached(missingPromptIndices.map((i) => baseMessages[i]), callOptions, runnableConfig, startedRunManagers !== void 0 ? missingPromptIndices.map((i) => startedRunManagers?.[i]) : void 0); + await Promise.all(results.generations.map(async (generation, index) => { + const promptIndex = missingPromptIndices[index]; + generations[promptIndex] = generation; + const prompt = BaseChatModel._convertInputToPromptValue(baseMessages[promptIndex]).toString(); + return cache.update(prompt, llmStringKey, generation); + })); + llmOutput = results.llmOutput ?? {}; } - return messages; + return { + generations, + llmOutput + }; } /** - * Formats the prompt with the given values. - * @param values The values to format the prompt with. - * @returns A promise that resolves to a string representing the formatted prompt. + * Get the parameters used to invoke the model */ - async format(values) { - const allValues = await this.mergePartialAndUserVariables(values); - const examples = await this.getExamples(allValues); - const exampleMessages = await Promise.all(examples.map((example) => this.examplePrompt.formatMessages(example))); - const exampleStrings = exampleMessages.flat().map((message) => message.content); - const template = [ - this.prefix, - ...exampleStrings, - this.suffix - ].join(this.exampleSeparator); - return renderTemplate(template, this.templateFormat, allValues); + invocationParams(_options) { + return {}; + } + _modelType() { + return "base_chat_model"; } /** - * Partially formats the prompt with the given values. - * @param values The values to partially format the prompt with. - * @returns A promise that resolves to an instance of `FewShotChatMessagePromptTemplate` with the given values partially formatted. + * Generates a prompt based on the input prompt values. + * @param promptValues An array of BasePromptValue instances. + * @param options The call options or an array of stop sequences. + * @param callbacks The callbacks for the language model. + * @returns A Promise that resolves to an LLMResult. */ - async partial(values) { - const newInputVariables = this.inputVariables.filter((variable) => !(variable in values)); - const newPartialVariables = { - ...this.partialVariables ?? {}, - ...values - }; - const promptDict = { - ...this, - inputVariables: newInputVariables, - partialVariables: newPartialVariables - }; - return new FewShotChatMessagePromptTemplate(promptDict); + async generatePrompt(promptValues, options, callbacks) { + const promptMessages = promptValues.map((promptValue) => promptValue.toChatMessages()); + return this.generate(promptMessages, options, callbacks); + } + withStructuredOutput(outputSchema, config) { + if (typeof this.bindTools !== "function") throw new Error(`Chat model must implement ".bindTools()" to use withStructuredOutput.`); + if (config?.strict) throw new Error(`"strict" mode is not supported for this model by default.`); + const schema = outputSchema; + const name = config?.name; + const description = getSchemaDescription(schema) ?? "A function available to call."; + const method = config?.method; + const includeRaw = config?.includeRaw; + if (method === "jsonMode") throw new Error(`Base withStructuredOutput implementation only supports "functionCalling" as a method.`); + let functionName = name ?? "extract"; + let tools; + if (isInteropZodSchema(schema)) tools = [{ + type: "function", + function: { + name: functionName, + description, + parameters: toJsonSchema(schema) + } + }]; + else { + if ("name" in schema) functionName = schema.name; + tools = [{ + type: "function", + function: { + name: functionName, + description, + parameters: schema + } + }]; + } + const llm = this.bindTools(tools); + const outputParser = RunnableLambda.from((input) => { + if (!AIMessageChunk.isInstance(input)) throw new Error("Input is not an AIMessageChunk."); + if (!input.tool_calls || input.tool_calls.length === 0) throw new Error("No tool calls found in the response."); + const toolCall = input.tool_calls.find((tc) => tc.name === functionName); + if (!toolCall) throw new Error(`No tool call found with name ${functionName}.`); + return toolCall.args; + }); + if (!includeRaw) return llm.pipe(outputParser).withConfig({ runName: "StructuredOutput" }); + const parserAssign = RunnablePassthrough.assign({ parsed: (input, config$1) => outputParser.invoke(input.raw, config$1) }); + const parserNone = RunnablePassthrough.assign({ parsed: () => null }); + const parsedWithFallback = parserAssign.withFallbacks({ fallbacks: [parserNone] }); + return RunnableSequence.from([{ raw: llm }, parsedWithFallback]).withConfig({ runName: "StructuredOutputRunnable" }); + } +}; +/** +* An abstract class that extends BaseChatModel and provides a simple +* implementation of _generate. +*/ +var SimpleChatModel = class extends BaseChatModel { + async _generate(messages, options, runManager) { + const text = await this._call(messages, options, runManager); + const message = new AIMessage(text); + if (typeof message.content !== "string") throw new Error("Cannot generate with a simple chat model when output is not a string."); + return { generations: [{ + text: message.content, + message + }] }; } }; //#endregion -//# sourceMappingURL=few_shot.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/pipeline.js +//# sourceMappingURL=chat_models.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/llms.js -//#region src/prompts/pipeline.ts + + + + +//#region src/language_models/llms.ts +var llms_exports = {}; +__export(llms_exports, { + BaseLLM: () => BaseLLM, + LLM: () => LLM +}); /** -* Class that handles a sequence of prompts, each of which may require -* different input variables. Includes methods for formatting these -* prompts, extracting required input values, and handling partial -* prompts. -* @example -* ```typescript -* const composedPrompt = new PipelinePromptTemplate({ -* pipelinePrompts: [ -* { -* name: "introduction", -* prompt: PromptTemplate.fromTemplate(`You are impersonating {person}.`), -* }, -* { -* name: "example", -* prompt: PromptTemplate.fromTemplate( -* `Here's an example of an interaction: -* Q: {example_q} -* A: {example_a}`, -* ), -* }, -* { -* name: "start", -* prompt: PromptTemplate.fromTemplate( -* `Now, do this for real! -* Q: {input} -* A:`, -* ), -* }, -* ], -* finalPrompt: PromptTemplate.fromTemplate( -* `{introduction} -* {example} -* {start}`, -* ), -* }); -* -* const formattedPrompt = await composedPrompt.format({ -* person: "Elon Musk", -* example_q: `What's your favorite car?`, -* example_a: "Tesla", -* input: `What's your favorite social media site?`, -* }); -* ``` +* LLM Wrapper. Takes in a prompt (or prompts) and returns a string. */ -var PipelinePromptTemplate = class PipelinePromptTemplate extends BasePromptTemplate { - static lc_name() { - return "PipelinePromptTemplate"; - } - pipelinePrompts; - finalPrompt; - constructor(input) { - super({ - ...input, - inputVariables: [] - }); - this.pipelinePrompts = input.pipelinePrompts; - this.finalPrompt = input.finalPrompt; - this.inputVariables = this.computeInputValues(); - } +var BaseLLM = class BaseLLM extends BaseLanguageModel { + lc_namespace = [ + "langchain", + "llms", + this._llmType() + ]; /** - * Computes the input values required by the pipeline prompts. - * @returns Array of input values required by the pipeline prompts. + * This method takes an input and options, and returns a string. It + * converts the input to a prompt value and generates a result based on + * the prompt. + * @param input Input for the LLM. + * @param options Options for the LLM call. + * @returns A string result based on the prompt. */ - computeInputValues() { - const intermediateValues = this.pipelinePrompts.map((pipelinePrompt) => pipelinePrompt.name); - const inputValues = this.pipelinePrompts.map((pipelinePrompt) => pipelinePrompt.prompt.inputVariables.filter((inputValue) => !intermediateValues.includes(inputValue))).flat(); - return [...new Set(inputValues)]; + async invoke(input, options) { + const promptValue = BaseLLM._convertInputToPromptValue(input); + const result = await this.generatePrompt([promptValue], options, options?.callbacks); + return result.generations[0][0].text; } - static extractRequiredInputValues(allValues, requiredValueNames) { - return requiredValueNames.reduce((requiredValues, valueName) => { - requiredValues[valueName] = allValues[valueName]; - return requiredValues; - }, {}); + async *_streamResponseChunks(_input, _options, _runManager) { + throw new Error("Not implemented."); } - /** - * Formats the pipeline prompts based on the provided input values. - * @param values Input values to format the pipeline prompts. - * @returns Promise that resolves with the formatted input values. - */ - async formatPipelinePrompts(values) { - const allValues = await this.mergePartialAndUserVariables(values); - for (const { name: pipelinePromptName, prompt: pipelinePrompt } of this.pipelinePrompts) { - const pipelinePromptInputValues = PipelinePromptTemplate.extractRequiredInputValues(allValues, pipelinePrompt.inputVariables); - if (pipelinePrompt instanceof ChatPromptTemplate) allValues[pipelinePromptName] = await pipelinePrompt.formatMessages(pipelinePromptInputValues); - else allValues[pipelinePromptName] = await pipelinePrompt.format(pipelinePromptInputValues); + _separateRunnableConfigFromCallOptionsCompat(options) { + const [runnableConfig, callOptions] = super._separateRunnableConfigFromCallOptions(options); + callOptions.signal = runnableConfig.signal; + return [runnableConfig, callOptions]; + } + async *_streamIterator(input, options) { + if (this._streamResponseChunks === BaseLLM.prototype._streamResponseChunks) yield this.invoke(input, options); + else { + const prompt = BaseLLM._convertInputToPromptValue(input); + const [runnableConfig, callOptions] = this._separateRunnableConfigFromCallOptionsCompat(options); + const callbackManager_ = await CallbackManager.configure(runnableConfig.callbacks, this.callbacks, runnableConfig.tags, this.tags, runnableConfig.metadata, this.metadata, { verbose: this.verbose }); + const extra = { + options: callOptions, + invocation_params: this?.invocationParams(callOptions), + batch_size: 1 + }; + const runManagers = await callbackManager_?.handleLLMStart(this.toJSON(), [prompt.toString()], runnableConfig.runId, void 0, extra, void 0, void 0, runnableConfig.runName); + let generation = new GenerationChunk({ text: "" }); + try { + for await (const chunk of this._streamResponseChunks(prompt.toString(), callOptions, runManagers?.[0])) { + if (!generation) generation = chunk; + else generation = generation.concat(chunk); + if (typeof chunk.text === "string") yield chunk.text; + } + } catch (err) { + await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMError(err))); + throw err; + } + await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMEnd({ generations: [[generation]] }))); } - return PipelinePromptTemplate.extractRequiredInputValues(allValues, this.finalPrompt.inputVariables); } /** - * Formats the final prompt value based on the provided input values. - * @param values Input values to format the final prompt value. - * @returns Promise that resolves with the formatted final prompt value. + * This method takes prompt values, options, and callbacks, and generates + * a result based on the prompts. + * @param promptValues Prompt values for the LLM. + * @param options Options for the LLM call. + * @param callbacks Callbacks for the LLM call. + * @returns An LLMResult based on the prompts. */ - async formatPromptValue(values) { - return this.finalPrompt.formatPromptValue(await this.formatPipelinePrompts(values)); - } - async format(values) { - return this.finalPrompt.format(await this.formatPipelinePrompts(values)); + async generatePrompt(promptValues, options, callbacks) { + const prompts = promptValues.map((promptValue) => promptValue.toString()); + return this.generate(prompts, options, callbacks); } /** - * Handles partial prompts, which are prompts that have been partially - * filled with input values. - * @param values Partial input values. - * @returns Promise that resolves with a new PipelinePromptTemplate instance with updated input variables. + * Get the parameters used to invoke the model */ - async partial(values) { - const promptDict = { ...this }; - promptDict.inputVariables = this.inputVariables.filter((iv) => !(iv in values)); - promptDict.partialVariables = { - ...this.partialVariables ?? {}, - ...values - }; - return new PipelinePromptTemplate(promptDict); + invocationParams(_options) { + return {}; } - serialize() { - throw new Error("Not implemented."); + _flattenLLMResult(llmResult) { + const llmResults = []; + for (let i = 0; i < llmResult.generations.length; i += 1) { + const genList = llmResult.generations[i]; + if (i === 0) llmResults.push({ + generations: [genList], + llmOutput: llmResult.llmOutput + }); + else { + const llmOutput = llmResult.llmOutput ? { + ...llmResult.llmOutput, + tokenUsage: {} + } : void 0; + llmResults.push({ + generations: [genList], + llmOutput + }); + } + } + return llmResults; } - _getPromptType() { - return "pipeline"; + /** @ignore */ + async _generateUncached(prompts, parsedOptions, handledOptions, startedRunManagers) { + let runManagers; + if (startedRunManagers !== void 0 && startedRunManagers.length === prompts.length) runManagers = startedRunManagers; + else { + const callbackManager_ = await CallbackManager.configure(handledOptions.callbacks, this.callbacks, handledOptions.tags, this.tags, handledOptions.metadata, this.metadata, { verbose: this.verbose }); + const extra = { + options: parsedOptions, + invocation_params: this?.invocationParams(parsedOptions), + batch_size: prompts.length + }; + runManagers = await callbackManager_?.handleLLMStart(this.toJSON(), prompts, handledOptions.runId, void 0, extra, void 0, void 0, handledOptions?.runName); + } + const hasStreamingHandler = !!runManagers?.[0].handlers.find(callbackHandlerPrefersStreaming); + let output; + if (hasStreamingHandler && prompts.length === 1 && this._streamResponseChunks !== BaseLLM.prototype._streamResponseChunks) try { + const stream = await this._streamResponseChunks(prompts[0], parsedOptions, runManagers?.[0]); + let aggregated; + for await (const chunk of stream) if (aggregated === void 0) aggregated = chunk; + else aggregated = concat(aggregated, chunk); + if (aggregated === void 0) throw new Error("Received empty response from chat model call."); + output = { + generations: [[aggregated]], + llmOutput: {} + }; + await runManagers?.[0].handleLLMEnd(output); + } catch (e) { + await runManagers?.[0].handleLLMError(e); + throw e; + } + else { + try { + output = await this._generate(prompts, parsedOptions, runManagers?.[0]); + } catch (err) { + await Promise.all((runManagers ?? []).map((runManager) => runManager?.handleLLMError(err))); + throw err; + } + const flattenedOutputs = this._flattenLLMResult(output); + await Promise.all((runManagers ?? []).map((runManager, i) => runManager?.handleLLMEnd(flattenedOutputs[i]))); + } + const runIds = runManagers?.map((manager) => manager.runId) || void 0; + Object.defineProperty(output, RUN_KEY, { + value: runIds ? { runIds } : void 0, + configurable: true + }); + return output; } -}; - -//#endregion - -//# sourceMappingURL=pipeline.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/structured.js - - - -//#region src/prompts/structured.ts -function isWithStructuredOutput(x) { - return typeof x === "object" && x != null && "withStructuredOutput" in x && typeof x.withStructuredOutput === "function"; -} -function isRunnableBinding(x) { - return typeof x === "object" && x != null && "lc_id" in x && Array.isArray(x.lc_id) && x.lc_id.join("/") === "langchain_core/runnables/RunnableBinding"; -} -var StructuredPrompt = class StructuredPrompt extends ChatPromptTemplate { - schema; - method; - lc_namespace = [ - "langchain_core", - "prompts", - "structured" - ]; - get lc_aliases() { - return { - ...super.lc_aliases, - schema: "schema_" + async _generateCached({ prompts, cache, llmStringKey, parsedOptions, handledOptions, runId }) { + const callbackManager_ = await CallbackManager.configure(handledOptions.callbacks, this.callbacks, handledOptions.tags, this.tags, handledOptions.metadata, this.metadata, { verbose: this.verbose }); + const extra = { + options: parsedOptions, + invocation_params: this?.invocationParams(parsedOptions), + batch_size: prompts.length + }; + const runManagers = await callbackManager_?.handleLLMStart(this.toJSON(), prompts, runId, void 0, extra, void 0, void 0, handledOptions?.runName); + const missingPromptIndices = []; + const results = await Promise.allSettled(prompts.map(async (prompt, index) => { + const result = await cache.lookup(prompt, llmStringKey); + if (result == null) missingPromptIndices.push(index); + return result; + })); + const cachedResults = results.map((result, index) => ({ + result, + runManager: runManagers?.[index] + })).filter(({ result }) => result.status === "fulfilled" && result.value != null || result.status === "rejected"); + const generations = []; + await Promise.all(cachedResults.map(async ({ result: promiseResult, runManager }, i) => { + if (promiseResult.status === "fulfilled") { + const result = promiseResult.value; + generations[i] = result.map((result$1) => { + result$1.generationInfo = { + ...result$1.generationInfo, + tokenUsage: {} + }; + return result$1; + }); + if (result.length) await runManager?.handleLLMNewToken(result[0].text); + return runManager?.handleLLMEnd({ generations: [result] }, void 0, void 0, void 0, { cached: true }); + } else { + await runManager?.handleLLMError(promiseResult.reason, void 0, void 0, void 0, { cached: true }); + return Promise.reject(promiseResult.reason); + } + })); + const output = { + generations, + missingPromptIndices, + startedRunManagers: runManagers }; + Object.defineProperty(output, RUN_KEY, { + value: runManagers ? { runIds: runManagers?.map((manager) => manager.runId) } : void 0, + configurable: true + }); + return output; } - constructor(input) { - super(input); - this.schema = input.schema; - this.method = input.method; + /** + * Run the LLM on the given prompts and input, handling caching. + */ + async generate(prompts, options, callbacks) { + if (!Array.isArray(prompts)) throw new Error("Argument 'prompts' is expected to be a string[]"); + let parsedOptions; + if (Array.isArray(options)) parsedOptions = { stop: options }; + else parsedOptions = options; + const [runnableConfig, callOptions] = this._separateRunnableConfigFromCallOptionsCompat(parsedOptions); + runnableConfig.callbacks = runnableConfig.callbacks ?? callbacks; + if (!this.cache) return this._generateUncached(prompts, callOptions, runnableConfig); + const { cache } = this; + const llmStringKey = this._getSerializedCacheKeyParametersForCall(callOptions); + const { generations, missingPromptIndices, startedRunManagers } = await this._generateCached({ + prompts, + cache, + llmStringKey, + parsedOptions: callOptions, + handledOptions: runnableConfig, + runId: runnableConfig.runId + }); + let llmOutput = {}; + if (missingPromptIndices.length > 0) { + const results = await this._generateUncached(missingPromptIndices.map((i) => prompts[i]), callOptions, runnableConfig, startedRunManagers !== void 0 ? missingPromptIndices.map((i) => startedRunManagers?.[i]) : void 0); + await Promise.all(results.generations.map(async (generation, index) => { + const promptIndex = missingPromptIndices[index]; + generations[promptIndex] = generation; + return cache.update(prompts[promptIndex], llmStringKey, generation); + })); + llmOutput = results.llmOutput ?? {}; + } + return { + generations, + llmOutput + }; } - pipe(coerceable) { - if (isWithStructuredOutput(coerceable)) return super.pipe(coerceable.withStructuredOutput(this.schema)); - if (isRunnableBinding(coerceable) && isWithStructuredOutput(coerceable.bound)) return super.pipe(new RunnableBinding({ - bound: coerceable.bound.withStructuredOutput(this.schema, ...this.method ? [{ method: this.method }] : []), - kwargs: coerceable.kwargs ?? {}, - config: coerceable.config, - configFactories: coerceable.configFactories - })); - throw new Error(`Structured prompts need to be piped to a language model that supports the "withStructuredOutput()" method.`); + /** + * Get the identifying parameters of the LLM. + */ + _identifyingParams() { + return {}; } - static fromMessagesAndSchema(promptMessages, schema, method) { - return StructuredPrompt.fromMessages(promptMessages, { - schema, - method - }); + _modelType() { + return "base_llm"; + } +}; +/** +* LLM class that provides a simpler interface to subclass than {@link BaseLLM}. +* +* Requires only implementing a simpler {@link _call} method instead of {@link _generate}. +* +* @augments BaseLLM +*/ +var LLM = class extends BaseLLM { + async _generate(prompts, options, runManager) { + const generations = await Promise.all(prompts.map((prompt, promptIndex) => this._call(prompt, { + ...options, + promptIndex + }, runManager).then((text) => [{ text }]))); + return { generations }; } }; //#endregion -//# sourceMappingURL=structured.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/index.js - - - - - - - - - - - - -//#region src/prompts/index.ts -var prompts_exports = {}; -__export(prompts_exports, { - AIMessagePromptTemplate: () => AIMessagePromptTemplate, - BaseChatPromptTemplate: () => BaseChatPromptTemplate, - BaseMessagePromptTemplate: () => BaseMessagePromptTemplate, - BaseMessageStringPromptTemplate: () => BaseMessageStringPromptTemplate, - BasePromptTemplate: () => BasePromptTemplate, - BaseStringPromptTemplate: () => BaseStringPromptTemplate, - ChatMessagePromptTemplate: () => ChatMessagePromptTemplate, - ChatPromptTemplate: () => ChatPromptTemplate, - DEFAULT_FORMATTER_MAPPING: () => DEFAULT_FORMATTER_MAPPING, - DEFAULT_PARSER_MAPPING: () => DEFAULT_PARSER_MAPPING, - DictPromptTemplate: () => DictPromptTemplate, - FewShotChatMessagePromptTemplate: () => FewShotChatMessagePromptTemplate, - FewShotPromptTemplate: () => FewShotPromptTemplate, - HumanMessagePromptTemplate: () => HumanMessagePromptTemplate, - ImagePromptTemplate: () => ImagePromptTemplate, - MessagesPlaceholder: () => MessagesPlaceholder, - PipelinePromptTemplate: () => PipelinePromptTemplate, - PromptTemplate: () => PromptTemplate, - StructuredPrompt: () => StructuredPrompt, - SystemMessagePromptTemplate: () => SystemMessagePromptTemplate, - checkValidTemplate: () => checkValidTemplate, - interpolateFString: () => interpolateFString, - interpolateMustache: () => interpolateMustache, - parseFString: () => parseFString, - parseMustache: () => parseMustache, - parseTemplate: () => template_parseTemplate, - renderTemplate: () => renderTemplate -}); +//# sourceMappingURL=llms.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/language_models/profile.js +//#region src/language_models/profile.ts +var profile_exports = {}; //#endregion -//# sourceMappingURL=index.js.map +//# sourceMappingURL=profile.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/runnables/router.js @@ -79164,7 +71200,430 @@ var BaseCumulativeTransformOutputParser = class extends BaseTransformOutputParse //#endregion -//# sourceMappingURL=transform.js.map +//# sourceMappingURL=transform.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/bytes.js + + +//#region src/output_parsers/bytes.ts +/** +* OutputParser that parses LLMResult into the top likely string and +* encodes it into bytes. +*/ +var BytesOutputParser = class extends BaseTransformOutputParser { + static lc_name() { + return "BytesOutputParser"; + } + lc_namespace = [ + "langchain_core", + "output_parsers", + "bytes" + ]; + lc_serializable = true; + textEncoder = new TextEncoder(); + parse(text) { + return Promise.resolve(this.textEncoder.encode(text)); + } + getFormatInstructions() { + return ""; + } +}; + +//#endregion + +//# sourceMappingURL=bytes.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/list.js + + + +//#region src/output_parsers/list.ts +/** +* Class to parse the output of an LLM call to a list. +* @augments BaseOutputParser +*/ +var ListOutputParser = class extends BaseTransformOutputParser { + re; + async *_transform(inputGenerator) { + let buffer = ""; + for await (const input of inputGenerator) { + if (typeof input === "string") buffer += input; + else buffer += input.content; + if (!this.re) { + const parts = await this.parse(buffer); + if (parts.length > 1) { + for (const part of parts.slice(0, -1)) yield [part]; + buffer = parts[parts.length - 1]; + } + } else { + const matches = [...buffer.matchAll(this.re)]; + if (matches.length > 1) { + let doneIdx = 0; + for (const match of matches.slice(0, -1)) { + yield [match[1]]; + doneIdx += (match.index ?? 0) + match[0].length; + } + buffer = buffer.slice(doneIdx); + } + } + } + for (const part of await this.parse(buffer)) yield [part]; + } +}; +/** +* Class to parse the output of an LLM call as a comma-separated list. +* @augments ListOutputParser +*/ +var CommaSeparatedListOutputParser = class extends ListOutputParser { + static lc_name() { + return "CommaSeparatedListOutputParser"; + } + lc_namespace = [ + "langchain_core", + "output_parsers", + "list" + ]; + lc_serializable = true; + /** + * Parses the given text into an array of strings, using a comma as the + * separator. If the parsing fails, throws an OutputParserException. + * @param text The text to parse. + * @returns An array of strings obtained by splitting the input text at each comma. + */ + async parse(text) { + try { + return text.trim().split(",").map((s) => s.trim()); + } catch { + throw new OutputParserException(`Could not parse output: ${text}`, text); + } + } + /** + * Provides instructions on the expected format of the response for the + * CommaSeparatedListOutputParser. + * @returns A string containing instructions on the expected format of the response. + */ + getFormatInstructions() { + return `Your response should be a list of comma separated values, eg: \`foo, bar, baz\``; + } +}; +/** +* Class to parse the output of an LLM call to a list with a specific length and separator. +* @augments ListOutputParser +*/ +var CustomListOutputParser = class extends ListOutputParser { + lc_namespace = [ + "langchain_core", + "output_parsers", + "list" + ]; + length; + separator; + constructor({ length, separator }) { + super(...arguments); + this.length = length; + this.separator = separator || ","; + } + /** + * Parses the given text into an array of strings, using the specified + * separator. If the parsing fails or the number of items in the list + * doesn't match the expected length, throws an OutputParserException. + * @param text The text to parse. + * @returns An array of strings obtained by splitting the input text at each occurrence of the specified separator. + */ + async parse(text) { + try { + const items = text.trim().split(this.separator).map((s) => s.trim()); + if (this.length !== void 0 && items.length !== this.length) throw new OutputParserException(`Incorrect number of items. Expected ${this.length}, got ${items.length}.`); + return items; + } catch (e) { + if (Object.getPrototypeOf(e) === OutputParserException.prototype) throw e; + throw new OutputParserException(`Could not parse output: ${text}`); + } + } + /** + * Provides instructions on the expected format of the response for the + * CustomListOutputParser, including the number of items and the + * separator. + * @returns A string containing instructions on the expected format of the response. + */ + getFormatInstructions() { + return `Your response should be a list of ${this.length === void 0 ? "" : `${this.length} `}items separated by "${this.separator}" (eg: \`foo${this.separator} bar${this.separator} baz\`)`; + } +}; +var NumberedListOutputParser = class extends ListOutputParser { + static lc_name() { + return "NumberedListOutputParser"; + } + lc_namespace = [ + "langchain_core", + "output_parsers", + "list" + ]; + lc_serializable = true; + getFormatInstructions() { + return `Your response should be a numbered list with each item on a new line. For example: \n\n1. foo\n\n2. bar\n\n3. baz`; + } + re = /\d+\.\s([^\n]+)/g; + async parse(text) { + return [...text.matchAll(this.re) ?? []].map((m) => m[1]); + } +}; +var MarkdownListOutputParser = class extends ListOutputParser { + static lc_name() { + return "NumberedListOutputParser"; + } + lc_namespace = [ + "langchain_core", + "output_parsers", + "list" + ]; + lc_serializable = true; + getFormatInstructions() { + return `Your response should be a numbered list with each item on a new line. For example: \n\n1. foo\n\n2. bar\n\n3. baz`; + } + re = /^\s*[-*]\s([^\n]+)$/gm; + async parse(text) { + return [...text.matchAll(this.re) ?? []].map((m) => m[1]); + } +}; + +//#endregion + +//# sourceMappingURL=list.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/string.js + + +//#region src/output_parsers/string.ts +/** +* OutputParser that parses LLMResult into the top likely string. +* @example +* ```typescript +* const promptTemplate = PromptTemplate.fromTemplate( +* "Tell me a joke about {topic}", +* ); +* +* const chain = RunnableSequence.from([ +* promptTemplate, +* new ChatOpenAI({ model: "gpt-4o-mini" }), +* new StringOutputParser(), +* ]); +* +* const result = await chain.invoke({ topic: "bears" }); +* console.log("What do you call a bear with no teeth? A gummy bear!"); +* ``` +*/ +var StringOutputParser = class extends BaseTransformOutputParser { + static lc_name() { + return "StrOutputParser"; + } + lc_namespace = [ + "langchain_core", + "output_parsers", + "string" + ]; + lc_serializable = true; + /** + * Parses a string output from an LLM call. This method is meant to be + * implemented by subclasses to define how a string output from an LLM + * should be parsed. + * @param text The string output from an LLM call. + * @param callbacks Optional callbacks. + * @returns A promise of the parsed output. + */ + parse(text) { + return Promise.resolve(text); + } + getFormatInstructions() { + return ""; + } + _textContentToString(content) { + return content.text; + } + _imageUrlContentToString(_content) { + throw new Error(`Cannot coerce a multimodal "image_url" message part into a string.`); + } + _messageContentToString(content) { + switch (content.type) { + case "text": + case "text_delta": + if ("text" in content) return this._textContentToString(content); + break; + case "image_url": + if ("image_url" in content) return this._imageUrlContentToString(content); + break; + default: throw new Error(`Cannot coerce "${content.type}" message part into a string.`); + } + throw new Error(`Invalid content type: ${content.type}`); + } + _baseMessageContentToString(content) { + return content.reduce((acc, item) => acc + this._messageContentToString(item), ""); + } +}; + +//#endregion + +//# sourceMappingURL=string.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/structured.js + + + + + +//#region src/output_parsers/structured.ts +var StructuredOutputParser = class extends BaseOutputParser { + static lc_name() { + return "StructuredOutputParser"; + } + lc_namespace = [ + "langchain", + "output_parsers", + "structured" + ]; + toJSON() { + return this.toJSONNotImplemented(); + } + constructor(schema) { + super(schema); + this.schema = schema; + } + /** + * Creates a new StructuredOutputParser from a Zod schema. + * @param schema The Zod schema which the output should match + * @returns A new instance of StructuredOutputParser. + */ + static fromZodSchema(schema) { + return new this(schema); + } + /** + * Creates a new StructuredOutputParser from a set of names and + * descriptions. + * @param schemas An object where each key is a name and each value is a description + * @returns A new instance of StructuredOutputParser. + */ + static fromNamesAndDescriptions(schemas) { + const zodSchema = objectType(Object.fromEntries(Object.entries(schemas).map(([name, description]) => [name, stringType().describe(description)]))); + return new this(zodSchema); + } + /** + * Returns a markdown code snippet with a JSON object formatted according + * to the schema. + * @param options Optional. The options for formatting the instructions + * @returns A markdown code snippet with a JSON object formatted according to the schema. + */ + getFormatInstructions() { + return `You must format your output as a JSON value that adheres to a given "JSON Schema" instance. + +"JSON Schema" is a declarative language that allows you to annotate and validate JSON documents. + +For example, the example "JSON Schema" instance {{"properties": {{"foo": {{"description": "a list of test words", "type": "array", "items": {{"type": "string"}}}}}}, "required": ["foo"]}} +would match an object with one required property, "foo". The "type" property specifies "foo" must be an "array", and the "description" property semantically describes it as "a list of test words". The items within "foo" must be strings. +Thus, the object {{"foo": ["bar", "baz"]}} is a well-formatted instance of this example "JSON Schema". The object {{"properties": {{"foo": ["bar", "baz"]}}}} is not well-formatted. + +Your output will be parsed and type-checked according to the provided schema instance, so make sure all fields in your output match the schema exactly and there are no trailing commas! + +Here is the JSON Schema instance your output must adhere to. Include the enclosing markdown codeblock: +\`\`\`json +${JSON.stringify(toJsonSchema(this.schema))} +\`\`\` +`; + } + /** + * Parses the given text according to the schema. + * @param text The text to parse + * @returns The parsed output. + */ + async parse(text) { + try { + const trimmedText = text.trim(); + const json = trimmedText.match(/^```(?:json)?\s*([\s\S]*?)```/)?.[1] || trimmedText.match(/```json\s*([\s\S]*?)```/)?.[1] || trimmedText; + const escapedJson = json.replace(/"([^"\\]*(\\.[^"\\]*)*)"/g, (_match, capturedGroup) => { + const escapedInsideQuotes = capturedGroup.replace(/\n/g, "\\n"); + return `"${escapedInsideQuotes}"`; + }).replace(/\n/g, ""); + return await interopParseAsync(this.schema, JSON.parse(escapedJson)); + } catch (e) { + throw new OutputParserException(`Failed to parse. Text: "${text}". Error: ${e}`, text); + } + } +}; +/** +* A specific type of `StructuredOutputParser` that parses JSON data +* formatted as a markdown code snippet. +*/ +var JsonMarkdownStructuredOutputParser = class extends StructuredOutputParser { + static lc_name() { + return "JsonMarkdownStructuredOutputParser"; + } + getFormatInstructions(options) { + const interpolationDepth = options?.interpolationDepth ?? 1; + if (interpolationDepth < 1) throw new Error("f string interpolation depth must be at least 1"); + return `Return a markdown code snippet with a JSON object formatted to look like:\n\`\`\`json\n${this._schemaToInstruction(toJsonSchema(this.schema)).replaceAll("{", "{".repeat(interpolationDepth)).replaceAll("}", "}".repeat(interpolationDepth))}\n\`\`\``; + } + _schemaToInstruction(schemaInput, indent = 2) { + const schema = schemaInput; + if ("type" in schema) { + let nullable = false; + let type; + if (Array.isArray(schema.type)) { + const nullIdx = schema.type.findIndex((type$1) => type$1 === "null"); + if (nullIdx !== -1) { + nullable = true; + schema.type.splice(nullIdx, 1); + } + type = schema.type.join(" | "); + } else type = schema.type; + if (schema.type === "object" && schema.properties) { + const description$1 = schema.description ? ` // ${schema.description}` : ""; + const properties = Object.entries(schema.properties).map(([key, value]) => { + const isOptional = schema.required?.includes(key) ? "" : " (optional)"; + return `${" ".repeat(indent)}"${key}": ${this._schemaToInstruction(value, indent + 2)}${isOptional}`; + }).join("\n"); + return `{\n${properties}\n${" ".repeat(indent - 2)}}${description$1}`; + } + if (schema.type === "array" && schema.items) { + const description$1 = schema.description ? ` // ${schema.description}` : ""; + return `array[\n${" ".repeat(indent)}${this._schemaToInstruction(schema.items, indent + 2)}\n${" ".repeat(indent - 2)}] ${description$1}`; + } + const isNullable = nullable ? " (nullable)" : ""; + const description = schema.description ? ` // ${schema.description}` : ""; + return `${type}${description}${isNullable}`; + } + if ("anyOf" in schema) return schema.anyOf.map((s) => this._schemaToInstruction(s, indent)).join(`\n${" ".repeat(indent - 2)}`); + throw new Error("unsupported schema type"); + } + static fromZodSchema(schema) { + return new this(schema); + } + static fromNamesAndDescriptions(schemas) { + const zodSchema = objectType(Object.fromEntries(Object.entries(schemas).map(([name, description]) => [name, stringType().describe(description)]))); + return new this(zodSchema); + } +}; +/** +* A type of `StructuredOutputParser` that handles asymmetric input and +* output schemas. +*/ +var AsymmetricStructuredOutputParser = class extends BaseOutputParser { + structuredInputParser; + constructor({ inputSchema }) { + super(...arguments); + this.structuredInputParser = new JsonMarkdownStructuredOutputParser(inputSchema); + } + async parse(text) { + let parsedInput; + try { + parsedInput = await this.structuredInputParser.parse(text); + } catch (e) { + throw new OutputParserException(`Failed to parse. Text: "${text}". Error: ${e}`, text); + } + return this.outputProcessor(parsedInput); + } + getFormatInstructions() { + return this.structuredInputParser.getFormatInstructions(); + } +}; + +//#endregion + +//# sourceMappingURL=structured.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/json.js @@ -79209,3278 +71668,3031 @@ var JsonOutputParser = class extends BaseCumulativeTransformOutputParser { //#endregion //# sourceMappingURL=json.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/openai_tools/json_output_tools_parsers.js - - - - - - - -//#region src/output_parsers/openai_tools/json_output_tools_parsers.ts -function parseToolCall(rawToolCall, options) { - if (rawToolCall.function === void 0) return void 0; - let functionArgs; - if (options?.partial) try { - functionArgs = parsePartialJson(rawToolCall.function.arguments ?? "{}"); - } catch { - return void 0; - } - else try { - functionArgs = JSON.parse(rawToolCall.function.arguments); - } catch (e) { - throw new OutputParserException([ - `Function "${rawToolCall.function.name}" arguments:`, - ``, - rawToolCall.function.arguments, - ``, - `are not valid JSON.`, - `Error: ${e.message}` - ].join("\n")); - } - const parsedToolCall = { - name: rawToolCall.function.name, - args: functionArgs, - type: "tool_call" - }; - if (options?.returnId) parsedToolCall.id = rawToolCall.id; - return parsedToolCall; -} -function convertLangChainToolCallToOpenAI(toolCall) { - if (toolCall.id === void 0) throw new Error(`All OpenAI tool calls must have an "id" field.`); - return { - id: toolCall.id, - type: "function", - function: { - name: toolCall.name, - arguments: JSON.stringify(toolCall.args) - } - }; -} -function makeInvalidToolCall(rawToolCall, errorMsg) { - return { - name: rawToolCall.function?.name, - args: rawToolCall.function?.arguments, - id: rawToolCall.id, - error: errorMsg, - type: "invalid_tool_call" +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/sax-js/sax.js +//#region src/utils/sax-js/sax.ts +const initializeSax = function() { + const sax$1 = {}; + sax$1.parser = function(strict, opt) { + return new SAXParser(strict, opt); }; -} -/** -* Class for parsing the output of a tool-calling LLM into a JSON object. -*/ -var JsonOutputToolsParser = class extends BaseCumulativeTransformOutputParser { - static lc_name() { - return "JsonOutputToolsParser"; - } - returnId = false; - lc_namespace = [ - "langchain", - "output_parsers", - "openai_tools" + sax$1.SAXParser = SAXParser; + sax$1.SAXStream = SAXStream; + sax$1.createStream = createStream; + sax$1.MAX_BUFFER_LENGTH = 64 * 1024; + const buffers = [ + "comment", + "sgmlDecl", + "textNode", + "tagName", + "doctype", + "procInstName", + "procInstBody", + "entity", + "attribName", + "attribValue", + "cdata", + "script" ]; - lc_serializable = true; - constructor(fields) { - super(fields); - this.returnId = fields?.returnId ?? this.returnId; - } - _diff() { - throw new Error("Not supported."); + sax$1.EVENTS = [ + "text", + "processinginstruction", + "sgmldeclaration", + "doctype", + "comment", + "opentagstart", + "attribute", + "opentag", + "closetag", + "opencdata", + "cdata", + "closecdata", + "error", + "end", + "ready", + "script", + "opennamespace", + "closenamespace" + ]; + function SAXParser(strict, opt) { + if (!(this instanceof SAXParser)) return new SAXParser(strict, opt); + var parser = this; + clearBuffers(parser); + parser.q = parser.c = ""; + parser.bufferCheckPosition = sax$1.MAX_BUFFER_LENGTH; + parser.opt = opt || {}; + parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags; + parser.looseCase = parser.opt.lowercase ? "toLowerCase" : "toUpperCase"; + parser.tags = []; + parser.closed = parser.closedRoot = parser.sawRoot = false; + parser.tag = parser.error = null; + parser.strict = !!strict; + parser.noscript = !!(strict || parser.opt.noscript); + parser.state = S.BEGIN; + parser.strictEntities = parser.opt.strictEntities; + parser.ENTITIES = parser.strictEntities ? Object.create(sax$1.XML_ENTITIES) : Object.create(sax$1.ENTITIES); + parser.attribList = []; + if (parser.opt.xmlns) parser.ns = Object.create(rootNS); + parser.trackPosition = parser.opt.position !== false; + if (parser.trackPosition) parser.position = parser.line = parser.column = 0; + emit(parser, "onready"); } - async parse() { - throw new Error("Not implemented."); + if (!Object.create) Object.create = function(o) { + function F() {} + F.prototype = o; + var newf = new F(); + return newf; + }; + if (!Object.keys) Object.keys = function(o) { + var a = []; + for (var i in o) if (o.hasOwnProperty(i)) a.push(i); + return a; + }; + function checkBufferLength(parser) { + var maxAllowed = Math.max(sax$1.MAX_BUFFER_LENGTH, 10); + var maxActual = 0; + for (var i = 0, l = buffers.length; i < l; i++) { + var len = parser[buffers[i]].length; + if (len > maxAllowed) switch (buffers[i]) { + case "textNode": + closeText(parser); + break; + case "cdata": + emitNode(parser, "oncdata", parser.cdata); + parser.cdata = ""; + break; + case "script": + emitNode(parser, "onscript", parser.script); + parser.script = ""; + break; + default: error(parser, "Max buffer length exceeded: " + buffers[i]); + } + maxActual = Math.max(maxActual, len); + } + var m = sax$1.MAX_BUFFER_LENGTH - maxActual; + parser.bufferCheckPosition = m + parser.position; } - async parseResult(generations) { - const result = await this.parsePartialResult(generations, false); - return result; + function clearBuffers(parser) { + for (var i = 0, l = buffers.length; i < l; i++) parser[buffers[i]] = ""; } - /** - * Parses the output and returns a JSON object. If `argsOnly` is true, - * only the arguments of the function call are returned. - * @param generations The output of the LLM to parse. - * @returns A JSON object representation of the function call or its arguments. - */ - async parsePartialResult(generations, partial = true) { - const message = generations[0].message; - let toolCalls; - if (isAIMessage(message) && message.tool_calls?.length) toolCalls = message.tool_calls.map((toolCall) => { - const { id,...rest } = toolCall; - if (!this.returnId) return rest; - return { - id, - ...rest - }; - }); - else if (message.additional_kwargs.tool_calls !== void 0) { - const rawToolCalls = JSON.parse(JSON.stringify(message.additional_kwargs.tool_calls)); - toolCalls = rawToolCalls.map((rawToolCall) => { - return parseToolCall(rawToolCall, { - returnId: this.returnId, - partial - }); - }); + function flushBuffers(parser) { + closeText(parser); + if (parser.cdata !== "") { + emitNode(parser, "oncdata", parser.cdata); + parser.cdata = ""; } - if (!toolCalls) return []; - const parsedToolCalls = []; - for (const toolCall of toolCalls) if (toolCall !== void 0) { - const backwardsCompatibleToolCall = { - type: toolCall.name, - args: toolCall.args, - id: toolCall.id - }; - parsedToolCalls.push(backwardsCompatibleToolCall); + if (parser.script !== "") { + emitNode(parser, "onscript", parser.script); + parser.script = ""; } - return parsedToolCalls; - } -}; -/** -* Class for parsing the output of a tool-calling LLM into a JSON object if you are -* expecting only a single tool to be called. -*/ -var JsonOutputKeyToolsParser = class extends JsonOutputToolsParser { - static lc_name() { - return "JsonOutputKeyToolsParser"; - } - lc_namespace = [ - "langchain", - "output_parsers", - "openai_tools" - ]; - lc_serializable = true; - returnId = false; - /** The type of tool calls to return. */ - keyName; - /** Whether to return only the first tool call. */ - returnSingle = false; - zodSchema; - constructor(params) { - super(params); - this.keyName = params.keyName; - this.returnSingle = params.returnSingle ?? this.returnSingle; - this.zodSchema = params.zodSchema; - } - async _validateResult(result) { - if (this.zodSchema === void 0) return result; - const zodParsedResult = await interopSafeParseAsync(this.zodSchema, result); - if (zodParsedResult.success) return zodParsedResult.data; - else throw new OutputParserException(`Failed to parse. Text: "${JSON.stringify(result, null, 2)}". Error: ${JSON.stringify(zodParsedResult.error?.issues)}`, JSON.stringify(result, null, 2)); - } - async parsePartialResult(generations) { - const results = await super.parsePartialResult(generations); - const matchingResults = results.filter((result) => result.type === this.keyName); - let returnedValues = matchingResults; - if (!matchingResults.length) return void 0; - if (!this.returnId) returnedValues = matchingResults.map((result) => result.args); - if (this.returnSingle) return returnedValues[0]; - return returnedValues; - } - async parseResult(generations) { - const results = await super.parsePartialResult(generations, false); - const matchingResults = results.filter((result) => result.type === this.keyName); - let returnedValues = matchingResults; - if (!matchingResults.length) return void 0; - if (!this.returnId) returnedValues = matchingResults.map((result) => result.args); - if (this.returnSingle) return this._validateResult(returnedValues[0]); - const toolCallResults = await Promise.all(returnedValues.map((value) => this._validateResult(value))); - return toolCallResults; - } -}; - -//#endregion - -//# sourceMappingURL=json_output_tools_parsers.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/openai_tools/index.js - - - -//#region src/output_parsers/openai_tools/index.ts -var openai_tools_exports = {}; -__export(openai_tools_exports, { - JsonOutputKeyToolsParser: () => JsonOutputKeyToolsParser, - JsonOutputToolsParser: () => JsonOutputToolsParser, - convertLangChainToolCallToOpenAI: () => convertLangChainToolCallToOpenAI, - makeInvalidToolCall: () => makeInvalidToolCall, - parseToolCall: () => parseToolCall -}); - -//#endregion - -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/types/stream.js -//#region src/types/stream.ts -var stream_stream_exports = {}; - -//#endregion - -//# sourceMappingURL=stream.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tracers/run_collector.js - - - -//#region src/tracers/run_collector.ts -var run_collector_exports = {}; -__export(run_collector_exports, { RunCollectorCallbackHandler: () => RunCollectorCallbackHandler }); -/** -* A callback handler that collects traced runs and makes it easy to fetch the traced run object from calls through any langchain object. -* For instance, it makes it easy to fetch the run ID and then do things with that, such as log feedback. -*/ -var RunCollectorCallbackHandler = class extends BaseTracer { - /** The name of the callback handler. */ - name = "run_collector"; - /** The ID of the example. */ - exampleId; - /** An array of traced runs. */ - tracedRuns; - /** - * Creates a new instance of the RunCollectorCallbackHandler class. - * @param exampleId The ID of the example. - */ - constructor({ exampleId } = {}) { - super({ _awaitHandler: true }); - this.exampleId = exampleId; - this.tracedRuns = []; - } - /** - * Persists the given run object. - * @param run The run object to persist. - */ - async persistRun(run) { - const run_ = { ...run }; - run_.reference_example_id = this.exampleId; - this.tracedRuns.push(run_); - } -}; - -//#endregion - -//# sourceMappingURL=run_collector.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/openai_functions/json_output_functions_parsers.js - - - - - - - -//#region src/output_parsers/openai_functions/json_output_functions_parsers.ts -/** -* Class for parsing the output of an LLM. Can be configured to return -* only the arguments of the function call in the output. -*/ -var OutputFunctionsParser = class extends BaseLLMOutputParser { - static lc_name() { - return "OutputFunctionsParser"; - } - lc_namespace = [ - "langchain", - "output_parsers", - "openai_functions" - ]; - lc_serializable = true; - argsOnly = true; - constructor(config) { - super(); - this.argsOnly = config?.argsOnly ?? this.argsOnly; - } - /** - * Parses the output and returns a string representation of the function - * call or its arguments. - * @param generations The output of the LLM to parse. - * @returns A string representation of the function call or its arguments. - */ - async parseResult(generations) { - if ("message" in generations[0]) { - const gen = generations[0]; - const functionCall = gen.message.additional_kwargs.function_call; - if (!functionCall) throw new Error(`No function_call in message ${JSON.stringify(generations)}`); - if (!functionCall.arguments) throw new Error(`No arguments in function_call ${JSON.stringify(generations)}`); - if (this.argsOnly) return functionCall.arguments; - return JSON.stringify(functionCall); - } else throw new Error(`No message in generations ${JSON.stringify(generations)}`); - } -}; -/** -* Class for parsing the output of an LLM into a JSON object. Uses an -* instance of `OutputFunctionsParser` to parse the output. -*/ -var JsonOutputFunctionsParser = class extends BaseCumulativeTransformOutputParser { - static lc_name() { - return "JsonOutputFunctionsParser"; - } - lc_namespace = [ - "langchain", - "output_parsers", - "openai_functions" - ]; - lc_serializable = true; - outputParser; - argsOnly = true; - constructor(config) { - super(config); - this.argsOnly = config?.argsOnly ?? this.argsOnly; - this.outputParser = new OutputFunctionsParser(config); } - _diff(prev, next) { - if (!next) return void 0; - const ops = compare(prev ?? {}, next); - return ops; + SAXParser.prototype = { + end: function() { + end(this); + }, + write, + resume: function() { + this.error = null; + return this; + }, + close: function() { + return this.write(null); + }, + flush: function() { + flushBuffers(this); + } + }; + var Stream = ReadableStream; + if (!Stream) Stream = function() {}; + var streamWraps = sax$1.EVENTS.filter(function(ev) { + return ev !== "error" && ev !== "end"; + }); + function createStream(strict, opt) { + return new SAXStream(strict, opt); } - async parsePartialResult(generations) { - const generation = generations[0]; - if (!generation.message) return void 0; - const { message } = generation; - const functionCall = message.additional_kwargs.function_call; - if (!functionCall) return void 0; - if (this.argsOnly) return parsePartialJson(functionCall.arguments); - return { - ...functionCall, - arguments: parsePartialJson(functionCall.arguments) + function SAXStream(strict, opt) { + if (!(this instanceof SAXStream)) return new SAXStream(strict, opt); + Stream.apply(this); + this._parser = new SAXParser(strict, opt); + this.writable = true; + this.readable = true; + var me = this; + this._parser.onend = function() { + me.emit("end"); }; + this._parser.onerror = function(er) { + me.emit("error", er); + me._parser.error = null; + }; + this._decoder = null; + streamWraps.forEach(function(ev) { + Object.defineProperty(me, "on" + ev, { + get: function() { + return me._parser["on" + ev]; + }, + set: function(h) { + if (!h) { + me.removeAllListeners(ev); + me._parser["on" + ev] = h; + return h; + } + me.on(ev, h); + }, + enumerable: true, + configurable: false + }); + }); } - /** - * Parses the output and returns a JSON object. If `argsOnly` is true, - * only the arguments of the function call are returned. - * @param generations The output of the LLM to parse. - * @returns A JSON object representation of the function call or its arguments. - */ - async parseResult(generations) { - const result = await this.outputParser.parseResult(generations); - if (!result) throw new Error(`No result from "OutputFunctionsParser" ${JSON.stringify(generations)}`); - return this.parse(result); - } - async parse(text) { - const parsedResult = JSON.parse(text); - if (this.argsOnly) return parsedResult; - parsedResult.arguments = JSON.parse(parsedResult.arguments); - return parsedResult; - } - getFormatInstructions() { - return ""; + SAXStream.prototype = Object.create(Stream.prototype, { constructor: { value: SAXStream } }); + SAXStream.prototype.write = function(data) { + this._parser.write(data.toString()); + this.emit("data", data); + return true; + }; + SAXStream.prototype.end = function(chunk) { + if (chunk && chunk.length) this.write(chunk); + this._parser.end(); + return true; + }; + SAXStream.prototype.on = function(ev, handler) { + var me = this; + if (!me._parser["on" + ev] && streamWraps.indexOf(ev) !== -1) me._parser["on" + ev] = function() { + var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments); + args.splice(0, 0, ev); + me.emit.apply(me, args); + }; + return Stream.prototype.on.call(me, ev, handler); + }; + var CDATA = "[CDATA["; + var DOCTYPE = "DOCTYPE"; + var XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace"; + var XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/"; + var rootNS = { + xml: XML_NAMESPACE, + xmlns: XMLNS_NAMESPACE + }; + var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/; + var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/; + var entityStart = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/; + var entityBody = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/; + function isWhitespace(c) { + return c === " " || c === "\n" || c === "\r" || c === " "; } -}; -/** -* Class for parsing the output of an LLM into a JSON object and returning -* a specific attribute. Uses an instance of `JsonOutputFunctionsParser` -* to parse the output. -*/ -var JsonKeyOutputFunctionsParser = class extends BaseLLMOutputParser { - static lc_name() { - return "JsonKeyOutputFunctionsParser"; + function isQuote(c) { + return c === "\"" || c === "'"; } - lc_namespace = [ - "langchain", - "output_parsers", - "openai_functions" - ]; - lc_serializable = true; - outputParser = new JsonOutputFunctionsParser(); - attrName; - get lc_aliases() { - return { attrName: "key_name" }; + function isAttribEnd(c) { + return c === ">" || isWhitespace(c); } - constructor(fields) { - super(fields); - this.attrName = fields.attrName; + function isMatch(regex, c) { + return regex.test(c); } - /** - * Parses the output and returns a specific attribute of the parsed JSON - * object. - * @param generations The output of the LLM to parse. - * @returns The value of a specific attribute of the parsed JSON object. - */ - async parseResult(generations) { - const result = await this.outputParser.parseResult(generations); - return result[this.attrName]; + function notMatch(regex, c) { + return !isMatch(regex, c); } -}; - -//#endregion - -//# sourceMappingURL=json_output_functions_parsers.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/openai_functions/index.js - - - -//#region src/output_parsers/openai_functions/index.ts -var openai_functions_exports = {}; -__export(openai_functions_exports, { - JsonKeyOutputFunctionsParser: () => JsonKeyOutputFunctionsParser, - JsonOutputFunctionsParser: () => JsonOutputFunctionsParser, - OutputFunctionsParser: () => OutputFunctionsParser -}); - -//#endregion - -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/chunk_array.js - - -//#region src/utils/chunk_array.ts -var chunk_array_exports = {}; -__export(chunk_array_exports, { chunkArray: () => chunkArray }); -const chunkArray = (arr, chunkSize) => arr.reduce((chunks, elem, index) => { - const chunkIndex = Math.floor(index / chunkSize); - const chunk = chunks[chunkIndex] || []; - chunks[chunkIndex] = chunk.concat([elem]); - return chunks; -}, []); - -//#endregion - -//# sourceMappingURL=chunk_array.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tools/types.js - - - -//#region src/tools/types.ts -/** -* Confirm whether the inputted tool is an instance of `StructuredToolInterface`. -* -* @param {StructuredToolInterface | JSONSchema | undefined} tool The tool to check if it is an instance of `StructuredToolInterface`. -* @returns {tool is StructuredToolInterface} Whether the inputted tool is an instance of `StructuredToolInterface`. -*/ -function isStructuredTool(tool) { - return tool !== void 0 && Array.isArray(tool.lc_namespace); -} -/** -* Confirm whether the inputted tool is an instance of `RunnableToolLike`. -* -* @param {unknown | undefined} tool The tool to check if it is an instance of `RunnableToolLike`. -* @returns {tool is RunnableToolLike} Whether the inputted tool is an instance of `RunnableToolLike`. -*/ -function isRunnableToolLike(tool) { - return tool !== void 0 && Runnable.isRunnable(tool) && "lc_name" in tool.constructor && typeof tool.constructor.lc_name === "function" && tool.constructor.lc_name() === "RunnableToolLike"; -} -/** -* Confirm whether or not the tool contains the necessary properties to be considered a `StructuredToolParams`. -* -* @param {unknown | undefined} tool The object to check if it is a `StructuredToolParams`. -* @returns {tool is StructuredToolParams} Whether the inputted object is a `StructuredToolParams`. -*/ -function isStructuredToolParams(tool) { - return !!tool && typeof tool === "object" && "name" in tool && "schema" in tool && (isInteropZodSchema(tool.schema) || tool.schema != null && typeof tool.schema === "object" && "type" in tool.schema && typeof tool.schema.type === "string" && [ - "null", - "boolean", - "object", - "array", - "number", - "string" - ].includes(tool.schema.type)); -} -/** -* Whether or not the tool is one of StructuredTool, RunnableTool or StructuredToolParams. -* It returns `is StructuredToolParams` since that is the most minimal interface of the three, -* while still containing the necessary properties to be passed to a LLM for tool calling. -* -* @param {unknown | undefined} tool The tool to check if it is a LangChain tool. -* @returns {tool is StructuredToolParams} Whether the inputted tool is a LangChain tool. -*/ -function isLangChainTool(tool) { - return isStructuredToolParams(tool) || isRunnableToolLike(tool) || isStructuredTool(tool); -} - -//#endregion - -//# sourceMappingURL=types.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/function_calling.js - - - - -//#region src/utils/function_calling.ts -var function_calling_exports = {}; -__export(function_calling_exports, { - convertToOpenAIFunction: () => convertToOpenAIFunction, - convertToOpenAITool: () => convertToOpenAITool, - isLangChainTool: () => isLangChainTool, - isRunnableToolLike: () => isRunnableToolLike, - isStructuredTool: () => isStructuredTool, - isStructuredToolParams: () => isStructuredToolParams -}); -/** -* Formats a `StructuredTool` or `RunnableToolLike` instance into a format -* that is compatible with OpenAI function calling. If `StructuredTool` or -* `RunnableToolLike` has a zod schema, the output will be converted into a -* JSON schema, which is then used as the parameters for the OpenAI tool. -* -* @param {StructuredToolInterface | RunnableToolLike} tool The tool to convert to an OpenAI function. -* @returns {FunctionDefinition} The inputted tool in OpenAI function format. -*/ -function convertToOpenAIFunction(tool, fields) { - const fieldsCopy = typeof fields === "number" ? void 0 : fields; - return { - name: tool.name, - description: tool.description, - parameters: toJsonSchema(tool.schema), - ...fieldsCopy?.strict !== void 0 ? { strict: fieldsCopy.strict } : {} + var S = 0; + sax$1.STATE = { + BEGIN: S++, + BEGIN_WHITESPACE: S++, + TEXT: S++, + TEXT_ENTITY: S++, + OPEN_WAKA: S++, + SGML_DECL: S++, + SGML_DECL_QUOTED: S++, + DOCTYPE: S++, + DOCTYPE_QUOTED: S++, + DOCTYPE_DTD: S++, + DOCTYPE_DTD_QUOTED: S++, + COMMENT_STARTING: S++, + COMMENT: S++, + COMMENT_ENDING: S++, + COMMENT_ENDED: S++, + CDATA: S++, + CDATA_ENDING: S++, + CDATA_ENDING_2: S++, + PROC_INST: S++, + PROC_INST_BODY: S++, + PROC_INST_ENDING: S++, + OPEN_TAG: S++, + OPEN_TAG_SLASH: S++, + ATTRIB: S++, + ATTRIB_NAME: S++, + ATTRIB_NAME_SAW_WHITE: S++, + ATTRIB_VALUE: S++, + ATTRIB_VALUE_QUOTED: S++, + ATTRIB_VALUE_CLOSED: S++, + ATTRIB_VALUE_UNQUOTED: S++, + ATTRIB_VALUE_ENTITY_Q: S++, + ATTRIB_VALUE_ENTITY_U: S++, + CLOSE_TAG: S++, + CLOSE_TAG_SAW_WHITE: S++, + SCRIPT: S++, + SCRIPT_ENDING: S++ }; -} -/** -* Formats a `StructuredTool` or `RunnableToolLike` instance into a -* format that is compatible with OpenAI tool calling. If `StructuredTool` or -* `RunnableToolLike` has a zod schema, the output will be converted into a -* JSON schema, which is then used as the parameters for the OpenAI tool. -* -* @param {StructuredToolInterface | Record | RunnableToolLike} tool The tool to convert to an OpenAI tool. -* @returns {ToolDefinition} The inputted tool in OpenAI tool format. -*/ -function convertToOpenAITool(tool, fields) { - const fieldsCopy = typeof fields === "number" ? void 0 : fields; - let toolDef; - if (isLangChainTool(tool)) toolDef = { - type: "function", - function: convertToOpenAIFunction(tool) + sax$1.XML_ENTITIES = { + amp: "&", + gt: ">", + lt: "<", + quot: "\"", + apos: "'" }; - else toolDef = tool; - if (fieldsCopy?.strict !== void 0) toolDef.function.strict = fieldsCopy.strict; - return toolDef; -} - -//#endregion - -//# sourceMappingURL=function_calling.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/ir.js -//#region src/structured_query/ir.ts -const Operators = { - and: "and", - or: "or", - not: "not" -}; -const Comparators = { - eq: "eq", - ne: "ne", - lt: "lt", - gt: "gt", - lte: "lte", - gte: "gte" -}; -/** -* Abstract class for visiting expressions. Subclasses must implement -* visitOperation, visitComparison, and visitStructuredQuery methods. -*/ -var Visitor = class {}; -/** -* Abstract class representing an expression. Subclasses must implement -* the exprName property and the accept method. -*/ -var Expression = class { - accept(visitor) { - if (this.exprName === "Operation") return visitor.visitOperation(this); - else if (this.exprName === "Comparison") return visitor.visitComparison(this); - else if (this.exprName === "StructuredQuery") return visitor.visitStructuredQuery(this); - else throw new Error("Unknown Expression type"); - } -}; -/** -* Abstract class representing a filter directive. It extends the -* Expression class. -*/ -var FilterDirective = class extends Expression {}; -/** -* Class representing a comparison filter directive. It extends the -* FilterDirective class. -*/ -var Comparison = class extends FilterDirective { - exprName = "Comparison"; - constructor(comparator, attribute, value) { - super(); - this.comparator = comparator; - this.attribute = attribute; - this.value = value; - } -}; -/** -* Class representing an operation filter directive. It extends the -* FilterDirective class. -*/ -var Operation = class extends FilterDirective { - exprName = "Operation"; - constructor(operator, args) { - super(); - this.operator = operator; - this.args = args; + sax$1.ENTITIES = { + amp: "&", + gt: ">", + lt: "<", + quot: "\"", + apos: "'", + AElig: 198, + Aacute: 193, + Acirc: 194, + Agrave: 192, + Aring: 197, + Atilde: 195, + Auml: 196, + Ccedil: 199, + ETH: 208, + Eacute: 201, + Ecirc: 202, + Egrave: 200, + Euml: 203, + Iacute: 205, + Icirc: 206, + Igrave: 204, + Iuml: 207, + Ntilde: 209, + Oacute: 211, + Ocirc: 212, + Ograve: 210, + Oslash: 216, + Otilde: 213, + Ouml: 214, + THORN: 222, + Uacute: 218, + Ucirc: 219, + Ugrave: 217, + Uuml: 220, + Yacute: 221, + aacute: 225, + acirc: 226, + aelig: 230, + agrave: 224, + aring: 229, + atilde: 227, + auml: 228, + ccedil: 231, + eacute: 233, + ecirc: 234, + egrave: 232, + eth: 240, + euml: 235, + iacute: 237, + icirc: 238, + igrave: 236, + iuml: 239, + ntilde: 241, + oacute: 243, + ocirc: 244, + ograve: 242, + oslash: 248, + otilde: 245, + ouml: 246, + szlig: 223, + thorn: 254, + uacute: 250, + ucirc: 251, + ugrave: 249, + uuml: 252, + yacute: 253, + yuml: 255, + copy: 169, + reg: 174, + nbsp: 160, + iexcl: 161, + cent: 162, + pound: 163, + curren: 164, + yen: 165, + brvbar: 166, + sect: 167, + uml: 168, + ordf: 170, + laquo: 171, + not: 172, + shy: 173, + macr: 175, + deg: 176, + plusmn: 177, + sup1: 185, + sup2: 178, + sup3: 179, + acute: 180, + micro: 181, + para: 182, + middot: 183, + cedil: 184, + ordm: 186, + raquo: 187, + frac14: 188, + frac12: 189, + frac34: 190, + iquest: 191, + times: 215, + divide: 247, + OElig: 338, + oelig: 339, + Scaron: 352, + scaron: 353, + Yuml: 376, + fnof: 402, + circ: 710, + tilde: 732, + Alpha: 913, + Beta: 914, + Gamma: 915, + Delta: 916, + Epsilon: 917, + Zeta: 918, + Eta: 919, + Theta: 920, + Iota: 921, + Kappa: 922, + Lambda: 923, + Mu: 924, + Nu: 925, + Xi: 926, + Omicron: 927, + Pi: 928, + Rho: 929, + Sigma: 931, + Tau: 932, + Upsilon: 933, + Phi: 934, + Chi: 935, + Psi: 936, + Omega: 937, + alpha: 945, + beta: 946, + gamma: 947, + delta: 948, + epsilon: 949, + zeta: 950, + eta: 951, + theta: 952, + iota: 953, + kappa: 954, + lambda: 955, + mu: 956, + nu: 957, + xi: 958, + omicron: 959, + pi: 960, + rho: 961, + sigmaf: 962, + sigma: 963, + tau: 964, + upsilon: 965, + phi: 966, + chi: 967, + psi: 968, + omega: 969, + thetasym: 977, + upsih: 978, + piv: 982, + ensp: 8194, + emsp: 8195, + thinsp: 8201, + zwnj: 8204, + zwj: 8205, + lrm: 8206, + rlm: 8207, + ndash: 8211, + mdash: 8212, + lsquo: 8216, + rsquo: 8217, + sbquo: 8218, + ldquo: 8220, + rdquo: 8221, + bdquo: 8222, + dagger: 8224, + Dagger: 8225, + bull: 8226, + hellip: 8230, + permil: 8240, + prime: 8242, + Prime: 8243, + lsaquo: 8249, + rsaquo: 8250, + oline: 8254, + frasl: 8260, + euro: 8364, + image: 8465, + weierp: 8472, + real: 8476, + trade: 8482, + alefsym: 8501, + larr: 8592, + uarr: 8593, + rarr: 8594, + darr: 8595, + harr: 8596, + crarr: 8629, + lArr: 8656, + uArr: 8657, + rArr: 8658, + dArr: 8659, + hArr: 8660, + forall: 8704, + part: 8706, + exist: 8707, + empty: 8709, + nabla: 8711, + isin: 8712, + notin: 8713, + ni: 8715, + prod: 8719, + sum: 8721, + minus: 8722, + lowast: 8727, + radic: 8730, + prop: 8733, + infin: 8734, + ang: 8736, + and: 8743, + or: 8744, + cap: 8745, + cup: 8746, + int: 8747, + there4: 8756, + sim: 8764, + cong: 8773, + asymp: 8776, + ne: 8800, + equiv: 8801, + le: 8804, + ge: 8805, + sub: 8834, + sup: 8835, + nsub: 8836, + sube: 8838, + supe: 8839, + oplus: 8853, + otimes: 8855, + perp: 8869, + sdot: 8901, + lceil: 8968, + rceil: 8969, + lfloor: 8970, + rfloor: 8971, + lang: 9001, + rang: 9002, + loz: 9674, + spades: 9824, + clubs: 9827, + hearts: 9829, + diams: 9830 + }; + Object.keys(sax$1.ENTITIES).forEach(function(key) { + var e = sax$1.ENTITIES[key]; + var s$1 = typeof e === "number" ? String.fromCharCode(e) : e; + sax$1.ENTITIES[key] = s$1; + }); + for (var s in sax$1.STATE) sax$1.STATE[sax$1.STATE[s]] = s; + S = sax$1.STATE; + function emit(parser, event, data) { + parser[event] && parser[event](data); } -}; -/** -* Class representing a structured query expression. It extends the -* Expression class. -*/ -var StructuredQuery = class extends Expression { - exprName = "StructuredQuery"; - constructor(query, filter) { - super(); - this.query = query; - this.filter = filter; + function emitNode(parser, nodeType, data) { + if (parser.textNode) closeText(parser); + emit(parser, nodeType, data); } -}; - -//#endregion - -//# sourceMappingURL=ir.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/utils.js -//#region src/structured_query/utils.ts -/** -* Checks if the provided argument is an object and not an array. -*/ -function isObject(obj) { - return obj && typeof obj === "object" && !Array.isArray(obj); -} -/** -* Checks if a provided filter is empty. The filter can be a function, an -* object, a string, or undefined. -*/ -function isFilterEmpty(filter) { - if (!filter) return true; - if (typeof filter === "string" && filter.length > 0) return false; - if (typeof filter === "function") return false; - return isObject(filter) && Object.keys(filter).length === 0; -} -/** -* Checks if the provided value is an integer. -*/ -function isInt(value) { - if (typeof value === "number") return value % 1 === 0; - else if (typeof value === "string") { - const numberValue = parseInt(value, 10); - return !Number.isNaN(numberValue) && numberValue % 1 === 0 && numberValue.toString() === value; + function closeText(parser) { + parser.textNode = textopts(parser.opt, parser.textNode); + if (parser.textNode) emit(parser, "ontext", parser.textNode); + parser.textNode = ""; } - return false; -} -/** -* Checks if the provided value is a floating-point number. -*/ -function isFloat(value) { - if (typeof value === "number") return value % 1 !== 0; - else if (typeof value === "string") { - const numberValue = parseFloat(value); - return !Number.isNaN(numberValue) && numberValue % 1 !== 0 && numberValue.toString() === value; + function textopts(opt, text) { + if (opt.trim) text = text.trim(); + if (opt.normalize) text = text.replace(/\s+/g, " "); + return text; } - return false; -} -/** -* Checks if the provided value is a string that cannot be parsed into a -* number. -*/ -function isString(value) { - return typeof value === "string" && (Number.isNaN(parseFloat(value)) || parseFloat(value).toString() !== value); -} -/** -* Checks if the provided value is a boolean. -*/ -function isBoolean(value) { - return typeof value === "boolean"; -} -/** -* Casts a value that might be string or number to actual string or number. -* Since LLM might return back an integer/float as a string, we need to cast -* it back to a number, as many vector databases can't handle number as string -* values as a comparator. -*/ -function castValue(input) { - let value; - if (isString(input)) value = input; - else if (isInt(input)) value = parseInt(input, 10); - else if (isFloat(input)) value = parseFloat(input); - else if (isBoolean(input)) value = Boolean(input); - else throw new Error("Unsupported value type"); - return value; -} - -//#endregion - -//# sourceMappingURL=utils.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/base.js - - - -//#region src/structured_query/base.ts -/** -* Abstract class that provides a blueprint for creating specific -* translator classes. Defines two abstract methods: formatFunction and -* mergeFilters. -*/ -var BaseTranslator = class extends Visitor {}; -/** -* Class that extends the BaseTranslator class and provides concrete -* implementations for the abstract methods. Also declares three types: -* VisitOperationOutput, VisitComparisonOutput, and -* VisitStructuredQueryOutput, which are used as the return types for the -* visitOperation, visitComparison, and visitStructuredQuery methods -* respectively. -*/ -var BasicTranslator = class extends BaseTranslator { - allowedOperators; - allowedComparators; - constructor(opts) { - super(); - this.allowedOperators = opts?.allowedOperators ?? [Operators.and, Operators.or]; - this.allowedComparators = opts?.allowedComparators ?? [ - Comparators.eq, - Comparators.ne, - Comparators.gt, - Comparators.gte, - Comparators.lt, - Comparators.lte - ]; + function error(parser, er) { + closeText(parser); + if (parser.trackPosition) er += "\nLine: " + parser.line + "\nColumn: " + parser.column + "\nChar: " + parser.c; + er = new Error(er); + parser.error = er; + emit(parser, "onerror", er); + return parser; } - formatFunction(func) { - if (func in Comparators) { - if (this.allowedComparators.length > 0 && this.allowedComparators.indexOf(func) === -1) throw new Error(`Comparator ${func} not allowed. Allowed comparators: ${this.allowedComparators.join(", ")}`); - } else if (func in Operators) { - if (this.allowedOperators.length > 0 && this.allowedOperators.indexOf(func) === -1) throw new Error(`Operator ${func} not allowed. Allowed operators: ${this.allowedOperators.join(", ")}`); - } else throw new Error("Unknown comparator or operator"); - return `$${func}`; + function end(parser) { + if (parser.sawRoot && !parser.closedRoot) strictFail(parser, "Unclosed root tag"); + if (parser.state !== S.BEGIN && parser.state !== S.BEGIN_WHITESPACE && parser.state !== S.TEXT) error(parser, "Unexpected end"); + closeText(parser); + parser.c = ""; + parser.closed = true; + emit(parser, "onend"); + SAXParser.call(parser, parser.strict, parser.opt); + return parser; } - /** - * Visits an operation and returns a result. - * @param operation The operation to visit. - * @returns The result of visiting the operation. - */ - visitOperation(operation) { - const args = operation.args?.map((arg) => arg.accept(this)); - return { [this.formatFunction(operation.operator)]: args }; + function strictFail(parser, message) { + if (typeof parser !== "object" || !(parser instanceof SAXParser)) throw new Error("bad call to strictFail"); + if (parser.strict) error(parser, message); } - /** - * Visits a comparison and returns a result. - * @param comparison The comparison to visit. - * @returns The result of visiting the comparison. - */ - visitComparison(comparison) { - return { [comparison.attribute]: { [this.formatFunction(comparison.comparator)]: castValue(comparison.value) } }; + function newTag(parser) { + if (!parser.strict) parser.tagName = parser.tagName[parser.looseCase](); + var parent = parser.tags[parser.tags.length - 1] || parser; + var tag = parser.tag = { + name: parser.tagName, + attributes: {} + }; + if (parser.opt.xmlns) tag.ns = parent.ns; + parser.attribList.length = 0; + emitNode(parser, "onopentagstart", tag); } - /** - * Visits a structured query and returns a result. - * @param query The structured query to visit. - * @returns The result of visiting the structured query. - */ - visitStructuredQuery(query) { - let nextArg = {}; - if (query.filter) nextArg = { filter: query.filter.accept(this) }; - return nextArg; + function qname(name, attribute) { + var i = name.indexOf(":"); + var qualName = i < 0 ? ["", name] : name.split(":"); + var prefix = qualName[0]; + var local = qualName[1]; + if (attribute && name === "xmlns") { + prefix = "xmlns"; + local = ""; + } + return { + prefix, + local + }; } - mergeFilters(defaultFilter, generatedFilter, mergeType = "and", forceDefaultFilter = false) { - if (isFilterEmpty(defaultFilter) && isFilterEmpty(generatedFilter)) return void 0; - if (isFilterEmpty(defaultFilter) || mergeType === "replace") { - if (isFilterEmpty(generatedFilter)) return void 0; - return generatedFilter; + function attrib(parser) { + if (!parser.strict) parser.attribName = parser.attribName[parser.looseCase](); + if (parser.attribList.indexOf(parser.attribName) !== -1 || parser.tag.attributes.hasOwnProperty(parser.attribName)) { + parser.attribName = parser.attribValue = ""; + return; } - if (isFilterEmpty(generatedFilter)) { - if (forceDefaultFilter) return defaultFilter; - if (mergeType === "and") return void 0; - return defaultFilter; + if (parser.opt.xmlns) { + var qn = qname(parser.attribName, true); + var prefix = qn.prefix; + var local = qn.local; + if (prefix === "xmlns") if (local === "xml" && parser.attribValue !== XML_NAMESPACE) strictFail(parser, "xml: prefix must be bound to " + XML_NAMESPACE + "\nActual: " + parser.attribValue); + else if (local === "xmlns" && parser.attribValue !== XMLNS_NAMESPACE) strictFail(parser, "xmlns: prefix must be bound to " + XMLNS_NAMESPACE + "\nActual: " + parser.attribValue); + else { + var tag = parser.tag; + var parent = parser.tags[parser.tags.length - 1] || parser; + if (tag.ns === parent.ns) tag.ns = Object.create(parent.ns); + tag.ns[local] = parser.attribValue; + } + parser.attribList.push([parser.attribName, parser.attribValue]); + } else { + parser.tag.attributes[parser.attribName] = parser.attribValue; + emitNode(parser, "onattribute", { + name: parser.attribName, + value: parser.attribValue + }); } - if (mergeType === "and") return { $and: [defaultFilter, generatedFilter] }; - else if (mergeType === "or") return { $or: [defaultFilter, generatedFilter] }; - else throw new Error("Unknown merge type"); - } -}; - -//#endregion - -//# sourceMappingURL=base.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/functional.js - - - - -//#region src/structured_query/functional.ts -/** -* A class that extends `BaseTranslator` to translate structured queries -* into functional filters. -* @example -* ```typescript -* const functionalTranslator = new FunctionalTranslator(); -* const relevantDocuments = await functionalTranslator.getRelevantDocuments( -* "Which movies are rated higher than 8.5?", -* ); -* ``` -*/ -var FunctionalTranslator = class extends BaseTranslator { - allowedOperators = [Operators.and, Operators.or]; - allowedComparators = [ - Comparators.eq, - Comparators.ne, - Comparators.gt, - Comparators.gte, - Comparators.lt, - Comparators.lte - ]; - formatFunction() { - throw new Error("Not implemented"); + parser.attribName = parser.attribValue = ""; } - /** - * Returns the allowed comparators for a given data type. - * @param input The input value to get the allowed comparators for. - * @returns An array of allowed comparators for the input data type. - */ - getAllowedComparatorsForType(inputType) { - switch (inputType) { - case "string": return [ - Comparators.eq, - Comparators.ne, - Comparators.gt, - Comparators.gte, - Comparators.lt, - Comparators.lte - ]; - case "number": return [ - Comparators.eq, - Comparators.ne, - Comparators.gt, - Comparators.gte, - Comparators.lt, - Comparators.lte - ]; - case "boolean": return [Comparators.eq, Comparators.ne]; - default: throw new Error(`Unsupported data type: ${inputType}`); + function openTag(parser, selfClosing) { + if (parser.opt.xmlns) { + var tag = parser.tag; + var qn = qname(parser.tagName); + tag.prefix = qn.prefix; + tag.local = qn.local; + tag.uri = tag.ns[qn.prefix] || ""; + if (tag.prefix && !tag.uri) { + strictFail(parser, "Unbound namespace prefix: " + JSON.stringify(parser.tagName)); + tag.uri = qn.prefix; + } + var parent = parser.tags[parser.tags.length - 1] || parser; + if (tag.ns && parent.ns !== tag.ns) Object.keys(tag.ns).forEach(function(p) { + emitNode(parser, "onopennamespace", { + prefix: p, + uri: tag.ns[p] + }); + }); + for (var i = 0, l = parser.attribList.length; i < l; i++) { + var nv = parser.attribList[i]; + var name = nv[0]; + var value = nv[1]; + var qualName = qname(name, true); + var prefix = qualName.prefix; + var local = qualName.local; + var uri = prefix === "" ? "" : tag.ns[prefix] || ""; + var a = { + name, + value, + prefix, + local, + uri + }; + if (prefix && prefix !== "xmlns" && !uri) { + strictFail(parser, "Unbound namespace prefix: " + JSON.stringify(prefix)); + a.uri = prefix; + } + parser.tag.attributes[name] = a; + emitNode(parser, "onattribute", a); + } + parser.attribList.length = 0; } - } - /** - * Returns a function that performs a comparison based on the provided - * comparator. - * @param comparator The comparator to base the comparison function on. - * @returns A function that takes two arguments and returns a boolean based on the comparison. - */ - getComparatorFunction(comparator) { - switch (comparator) { - case Comparators.eq: return (a, b) => a === b; - case Comparators.ne: return (a, b) => a !== b; - case Comparators.gt: return (a, b) => a > b; - case Comparators.gte: return (a, b) => a >= b; - case Comparators.lt: return (a, b) => a < b; - case Comparators.lte: return (a, b) => a <= b; - default: throw new Error("Unknown comparator"); + parser.tag.isSelfClosing = !!selfClosing; + parser.sawRoot = true; + parser.tags.push(parser.tag); + emitNode(parser, "onopentag", parser.tag); + if (!selfClosing) { + if (!parser.noscript && parser.tagName.toLowerCase() === "script") parser.state = S.SCRIPT; + else parser.state = S.TEXT; + parser.tag = null; + parser.tagName = ""; } + parser.attribName = parser.attribValue = ""; + parser.attribList.length = 0; } - /** - * Returns a function that performs an operation based on the provided - * operator. - * @param operator The operator to base the operation function on. - * @returns A function that takes two boolean arguments and returns a boolean based on the operation. - */ - getOperatorFunction(operator) { - switch (operator) { - case Operators.and: return (a, b) => a && b; - case Operators.or: return (a, b) => a || b; - default: throw new Error("Unknown operator"); + function closeTag(parser) { + if (!parser.tagName) { + strictFail(parser, "Weird empty close tag."); + parser.textNode += ""; + parser.state = S.TEXT; + return; } + if (parser.script) { + if (parser.tagName !== "script") { + parser.script += ""; + parser.tagName = ""; + parser.state = S.SCRIPT; + return; + } + emitNode(parser, "onscript", parser.script); + parser.script = ""; + } + var t = parser.tags.length; + var tagName = parser.tagName; + if (!parser.strict) tagName = tagName[parser.looseCase](); + var closeTo = tagName; + while (t--) { + var close = parser.tags[t]; + if (close.name !== closeTo) strictFail(parser, "Unexpected close tag"); + else break; + } + if (t < 0) { + strictFail(parser, "Unmatched closing tag: " + parser.tagName); + parser.textNode += ""; + parser.state = S.TEXT; + return; + } + parser.tagName = tagName; + var s$1 = parser.tags.length; + while (s$1-- > t) { + var tag = parser.tag = parser.tags.pop(); + parser.tagName = parser.tag.name; + emitNode(parser, "onclosetag", parser.tagName); + var x = {}; + for (var i in tag.ns) x[i] = tag.ns[i]; + var parent = parser.tags[parser.tags.length - 1] || parser; + if (parser.opt.xmlns && tag.ns !== parent.ns) Object.keys(tag.ns).forEach(function(p) { + var n = tag.ns[p]; + emitNode(parser, "onclosenamespace", { + prefix: p, + uri: n + }); + }); + } + if (t === 0) parser.closedRoot = true; + parser.tagName = parser.attribValue = parser.attribName = ""; + parser.attribList.length = 0; + parser.state = S.TEXT; } - /** - * Visits the operation part of a structured query and translates it into - * a functional filter. - * @param operation The operation part of a structured query. - * @returns A function that takes a `Document` as an argument and returns a boolean based on the operation. - */ - visitOperation(operation) { - const { operator, args } = operation; - if (this.allowedOperators.includes(operator)) { - const operatorFunction = this.getOperatorFunction(operator); - return (document) => { - if (!args) return true; - return args.reduce((acc, arg) => { - const result = arg.accept(this); - if (typeof result === "function") return operatorFunction(acc, result(document)); - else throw new Error("Filter is not a function"); - }, true); - }; - } else throw new Error("Operator not allowed"); - } - /** - * Visits the comparison part of a structured query and translates it into - * a functional filter. - * @param comparison The comparison part of a structured query. - * @returns A function that takes a `Document` as an argument and returns a boolean based on the comparison. - */ - visitComparison(comparison) { - const { comparator, attribute, value } = comparison; - const undefinedTrue = [Comparators.ne]; - if (this.allowedComparators.includes(comparator)) { - if (!this.getAllowedComparatorsForType(typeof value).includes(comparator)) throw new Error(`'${comparator}' comparator not allowed to be used with ${typeof value}`); - const comparatorFunction = this.getComparatorFunction(comparator); - return (document) => { - const documentValue = document.metadata[attribute]; - if (documentValue === void 0) { - if (undefinedTrue.includes(comparator)) return true; - return false; - } - return comparatorFunction(documentValue, castValue(value)); - }; - } else throw new Error("Comparator not allowed"); - } - /** - * Visits a structured query and translates it into a functional filter. - * @param query The structured query to translate. - * @returns An object containing a `filter` property, which is a function that takes a `Document` as an argument and returns a boolean based on the structured query. - */ - visitStructuredQuery(query) { - if (!query.filter) return {}; - const filterFunction = query.filter?.accept(this); - if (typeof filterFunction !== "function") throw new Error("Structured query filter is not a function"); - return { filter: filterFunction }; - } - /** - * Merges two filters into one, based on the specified merge type. - * @param defaultFilter The default filter function. - * @param generatedFilter The generated filter function. - * @param mergeType The type of merge to perform. Can be 'and', 'or', or 'replace'. Default is 'and'. - * @returns A function that takes a `Document` as an argument and returns a boolean based on the merged filters, or `undefined` if both filters are empty. - */ - mergeFilters(defaultFilter, generatedFilter, mergeType = "and") { - if (isFilterEmpty(defaultFilter) && isFilterEmpty(generatedFilter)) return void 0; - if (isFilterEmpty(defaultFilter) || mergeType === "replace") { - if (isFilterEmpty(generatedFilter)) return void 0; - return generatedFilter; + function parseEntity(parser) { + var entity = parser.entity; + var entityLC = entity.toLowerCase(); + var num; + var numStr = ""; + if (parser.ENTITIES[entity]) return parser.ENTITIES[entity]; + if (parser.ENTITIES[entityLC]) return parser.ENTITIES[entityLC]; + entity = entityLC; + if (entity.charAt(0) === "#") if (entity.charAt(1) === "x") { + entity = entity.slice(2); + num = parseInt(entity, 16); + numStr = num.toString(16); + } else { + entity = entity.slice(1); + num = parseInt(entity, 10); + numStr = num.toString(10); } - if (isFilterEmpty(generatedFilter)) { - if (mergeType === "and") return void 0; - return defaultFilter; + entity = entity.replace(/^0+/, ""); + if (isNaN(num) || numStr.toLowerCase() !== entity) { + strictFail(parser, "Invalid character entity"); + return "&" + parser.entity + ";"; } - if (mergeType === "and") return (document) => defaultFilter(document) && generatedFilter(document); - else if (mergeType === "or") return (document) => defaultFilter(document) || generatedFilter(document); - else throw new Error("Unknown merge type"); + return String.fromCodePoint(num); } + function beginWhiteSpace(parser, c) { + if (c === "<") { + parser.state = S.OPEN_WAKA; + parser.startTagPosition = parser.position; + } else if (!isWhitespace(c)) { + strictFail(parser, "Non-whitespace before first tag."); + parser.textNode = c; + parser.state = S.TEXT; + } + } + function charAt(chunk, i) { + var result = ""; + if (i < chunk.length) result = chunk.charAt(i); + return result; + } + function write(chunk) { + var parser = this; + if (this.error) throw this.error; + if (parser.closed) return error(parser, "Cannot write after close. Assign an onready handler."); + if (chunk === null) return end(parser); + if (typeof chunk === "object") chunk = chunk.toString(); + var i = 0; + var c = ""; + while (true) { + c = charAt(chunk, i++); + parser.c = c; + if (!c) break; + if (parser.trackPosition) { + parser.position++; + if (c === "\n") { + parser.line++; + parser.column = 0; + } else parser.column++; + } + switch (parser.state) { + case S.BEGIN: + parser.state = S.BEGIN_WHITESPACE; + if (c === "") continue; + beginWhiteSpace(parser, c); + continue; + case S.BEGIN_WHITESPACE: + beginWhiteSpace(parser, c); + continue; + case S.TEXT: + if (parser.sawRoot && !parser.closedRoot) { + var starti = i - 1; + while (c && c !== "<" && c !== "&") { + c = charAt(chunk, i++); + if (c && parser.trackPosition) { + parser.position++; + if (c === "\n") { + parser.line++; + parser.column = 0; + } else parser.column++; + } + } + parser.textNode += chunk.substring(starti, i - 1); + } + if (c === "<" && !(parser.sawRoot && parser.closedRoot && !parser.strict)) { + parser.state = S.OPEN_WAKA; + parser.startTagPosition = parser.position; + } else { + if (!isWhitespace(c) && (!parser.sawRoot || parser.closedRoot)) strictFail(parser, "Text data outside of root node."); + if (c === "&") parser.state = S.TEXT_ENTITY; + else parser.textNode += c; + } + continue; + case S.SCRIPT: + if (c === "<") parser.state = S.SCRIPT_ENDING; + else parser.script += c; + continue; + case S.SCRIPT_ENDING: + if (c === "/") parser.state = S.CLOSE_TAG; + else { + parser.script += "<" + c; + parser.state = S.SCRIPT; + } + continue; + case S.OPEN_WAKA: + if (c === "!") { + parser.state = S.SGML_DECL; + parser.sgmlDecl = ""; + } else if (isWhitespace(c)) {} else if (isMatch(nameStart, c)) { + parser.state = S.OPEN_TAG; + parser.tagName = c; + } else if (c === "/") { + parser.state = S.CLOSE_TAG; + parser.tagName = ""; + } else if (c === "?") { + parser.state = S.PROC_INST; + parser.procInstName = parser.procInstBody = ""; + } else { + strictFail(parser, "Unencoded <"); + if (parser.startTagPosition + 1 < parser.position) { + var pad = parser.position - parser.startTagPosition; + c = new Array(pad).join(" ") + c; + } + parser.textNode += "<" + c; + parser.state = S.TEXT; + } + continue; + case S.SGML_DECL: + if ((parser.sgmlDecl + c).toUpperCase() === CDATA) { + emitNode(parser, "onopencdata"); + parser.state = S.CDATA; + parser.sgmlDecl = ""; + parser.cdata = ""; + } else if (parser.sgmlDecl + c === "--") { + parser.state = S.COMMENT; + parser.comment = ""; + parser.sgmlDecl = ""; + } else if ((parser.sgmlDecl + c).toUpperCase() === DOCTYPE) { + parser.state = S.DOCTYPE; + if (parser.doctype || parser.sawRoot) strictFail(parser, "Inappropriately located doctype declaration"); + parser.doctype = ""; + parser.sgmlDecl = ""; + } else if (c === ">") { + emitNode(parser, "onsgmldeclaration", parser.sgmlDecl); + parser.sgmlDecl = ""; + parser.state = S.TEXT; + } else if (isQuote(c)) { + parser.state = S.SGML_DECL_QUOTED; + parser.sgmlDecl += c; + } else parser.sgmlDecl += c; + continue; + case S.SGML_DECL_QUOTED: + if (c === parser.q) { + parser.state = S.SGML_DECL; + parser.q = ""; + } + parser.sgmlDecl += c; + continue; + case S.DOCTYPE: + if (c === ">") { + parser.state = S.TEXT; + emitNode(parser, "ondoctype", parser.doctype); + parser.doctype = true; + } else { + parser.doctype += c; + if (c === "[") parser.state = S.DOCTYPE_DTD; + else if (isQuote(c)) { + parser.state = S.DOCTYPE_QUOTED; + parser.q = c; + } + } + continue; + case S.DOCTYPE_QUOTED: + parser.doctype += c; + if (c === parser.q) { + parser.q = ""; + parser.state = S.DOCTYPE; + } + continue; + case S.DOCTYPE_DTD: + parser.doctype += c; + if (c === "]") parser.state = S.DOCTYPE; + else if (isQuote(c)) { + parser.state = S.DOCTYPE_DTD_QUOTED; + parser.q = c; + } + continue; + case S.DOCTYPE_DTD_QUOTED: + parser.doctype += c; + if (c === parser.q) { + parser.state = S.DOCTYPE_DTD; + parser.q = ""; + } + continue; + case S.COMMENT: + if (c === "-") parser.state = S.COMMENT_ENDING; + else parser.comment += c; + continue; + case S.COMMENT_ENDING: + if (c === "-") { + parser.state = S.COMMENT_ENDED; + parser.comment = textopts(parser.opt, parser.comment); + if (parser.comment) emitNode(parser, "oncomment", parser.comment); + parser.comment = ""; + } else { + parser.comment += "-" + c; + parser.state = S.COMMENT; + } + continue; + case S.COMMENT_ENDED: + if (c !== ">") { + strictFail(parser, "Malformed comment"); + parser.comment += "--" + c; + parser.state = S.COMMENT; + } else parser.state = S.TEXT; + continue; + case S.CDATA: + if (c === "]") parser.state = S.CDATA_ENDING; + else parser.cdata += c; + continue; + case S.CDATA_ENDING: + if (c === "]") parser.state = S.CDATA_ENDING_2; + else { + parser.cdata += "]" + c; + parser.state = S.CDATA; + } + continue; + case S.CDATA_ENDING_2: + if (c === ">") { + if (parser.cdata) emitNode(parser, "oncdata", parser.cdata); + emitNode(parser, "onclosecdata"); + parser.cdata = ""; + parser.state = S.TEXT; + } else if (c === "]") parser.cdata += "]"; + else { + parser.cdata += "]]" + c; + parser.state = S.CDATA; + } + continue; + case S.PROC_INST: + if (c === "?") parser.state = S.PROC_INST_ENDING; + else if (isWhitespace(c)) parser.state = S.PROC_INST_BODY; + else parser.procInstName += c; + continue; + case S.PROC_INST_BODY: + if (!parser.procInstBody && isWhitespace(c)) continue; + else if (c === "?") parser.state = S.PROC_INST_ENDING; + else parser.procInstBody += c; + continue; + case S.PROC_INST_ENDING: + if (c === ">") { + emitNode(parser, "onprocessinginstruction", { + name: parser.procInstName, + body: parser.procInstBody + }); + parser.procInstName = parser.procInstBody = ""; + parser.state = S.TEXT; + } else { + parser.procInstBody += "?" + c; + parser.state = S.PROC_INST_BODY; + } + continue; + case S.OPEN_TAG: + if (isMatch(nameBody, c)) parser.tagName += c; + else { + newTag(parser); + if (c === ">") openTag(parser); + else if (c === "/") parser.state = S.OPEN_TAG_SLASH; + else { + if (!isWhitespace(c)) strictFail(parser, "Invalid character in tag name"); + parser.state = S.ATTRIB; + } + } + continue; + case S.OPEN_TAG_SLASH: + if (c === ">") { + openTag(parser, true); + closeTag(parser); + } else { + strictFail(parser, "Forward-slash in opening tag not followed by >"); + parser.state = S.ATTRIB; + } + continue; + case S.ATTRIB: + if (isWhitespace(c)) continue; + else if (c === ">") openTag(parser); + else if (c === "/") parser.state = S.OPEN_TAG_SLASH; + else if (isMatch(nameStart, c)) { + parser.attribName = c; + parser.attribValue = ""; + parser.state = S.ATTRIB_NAME; + } else strictFail(parser, "Invalid attribute name"); + continue; + case S.ATTRIB_NAME: + if (c === "=") parser.state = S.ATTRIB_VALUE; + else if (c === ">") { + strictFail(parser, "Attribute without value"); + parser.attribValue = parser.attribName; + attrib(parser); + openTag(parser); + } else if (isWhitespace(c)) parser.state = S.ATTRIB_NAME_SAW_WHITE; + else if (isMatch(nameBody, c)) parser.attribName += c; + else strictFail(parser, "Invalid attribute name"); + continue; + case S.ATTRIB_NAME_SAW_WHITE: + if (c === "=") parser.state = S.ATTRIB_VALUE; + else if (isWhitespace(c)) continue; + else { + strictFail(parser, "Attribute without value"); + parser.tag.attributes[parser.attribName] = ""; + parser.attribValue = ""; + emitNode(parser, "onattribute", { + name: parser.attribName, + value: "" + }); + parser.attribName = ""; + if (c === ">") openTag(parser); + else if (isMatch(nameStart, c)) { + parser.attribName = c; + parser.state = S.ATTRIB_NAME; + } else { + strictFail(parser, "Invalid attribute name"); + parser.state = S.ATTRIB; + } + } + continue; + case S.ATTRIB_VALUE: + if (isWhitespace(c)) continue; + else if (isQuote(c)) { + parser.q = c; + parser.state = S.ATTRIB_VALUE_QUOTED; + } else { + strictFail(parser, "Unquoted attribute value"); + parser.state = S.ATTRIB_VALUE_UNQUOTED; + parser.attribValue = c; + } + continue; + case S.ATTRIB_VALUE_QUOTED: + if (c !== parser.q) { + if (c === "&") parser.state = S.ATTRIB_VALUE_ENTITY_Q; + else parser.attribValue += c; + continue; + } + attrib(parser); + parser.q = ""; + parser.state = S.ATTRIB_VALUE_CLOSED; + continue; + case S.ATTRIB_VALUE_CLOSED: + if (isWhitespace(c)) parser.state = S.ATTRIB; + else if (c === ">") openTag(parser); + else if (c === "/") parser.state = S.OPEN_TAG_SLASH; + else if (isMatch(nameStart, c)) { + strictFail(parser, "No whitespace between attributes"); + parser.attribName = c; + parser.attribValue = ""; + parser.state = S.ATTRIB_NAME; + } else strictFail(parser, "Invalid attribute name"); + continue; + case S.ATTRIB_VALUE_UNQUOTED: + if (!isAttribEnd(c)) { + if (c === "&") parser.state = S.ATTRIB_VALUE_ENTITY_U; + else parser.attribValue += c; + continue; + } + attrib(parser); + if (c === ">") openTag(parser); + else parser.state = S.ATTRIB; + continue; + case S.CLOSE_TAG: + if (!parser.tagName) if (isWhitespace(c)) continue; + else if (notMatch(nameStart, c)) if (parser.script) { + parser.script += "") closeTag(parser); + else if (isMatch(nameBody, c)) parser.tagName += c; + else if (parser.script) { + parser.script += "") closeTag(parser); + else strictFail(parser, "Invalid characters in closing tag"); + continue; + case S.TEXT_ENTITY: + case S.ATTRIB_VALUE_ENTITY_Q: + case S.ATTRIB_VALUE_ENTITY_U: + var returnState; + var buffer; + switch (parser.state) { + case S.TEXT_ENTITY: + returnState = S.TEXT; + buffer = "textNode"; + break; + case S.ATTRIB_VALUE_ENTITY_Q: + returnState = S.ATTRIB_VALUE_QUOTED; + buffer = "attribValue"; + break; + case S.ATTRIB_VALUE_ENTITY_U: + returnState = S.ATTRIB_VALUE_UNQUOTED; + buffer = "attribValue"; + break; + } + if (c === ";") if (parser.opt.unparsedEntities) { + var parsedEntity = parseEntity(parser); + parser.entity = ""; + parser.state = returnState; + parser.write(parsedEntity); + } else { + parser[buffer] += parseEntity(parser); + parser.entity = ""; + parser.state = returnState; + } + else if (isMatch(parser.entity.length ? entityBody : entityStart, c)) parser.entity += c; + else { + strictFail(parser, "Invalid character in entity name"); + parser[buffer] += "&" + parser.entity + c; + parser.entity = ""; + parser.state = returnState; + } + continue; + default: throw new Error(parser, "Unknown state: " + parser.state); + } + } + if (parser.position >= parser.bufferCheckPosition) checkBufferLength(parser); + return parser; + } + /*! http://mths.be/fromcodepoint v0.1.0 by @mathias */ + /* istanbul ignore next */ + if (!String.fromCodePoint) (function() { + var stringFromCharCode = String.fromCharCode; + var floor = Math.floor; + var fromCodePoint = function() { + var MAX_SIZE = 16384; + var codeUnits = []; + var highSurrogate; + var lowSurrogate; + var index = -1; + var length = arguments.length; + if (!length) return ""; + var result = ""; + while (++index < length) { + var codePoint = Number(arguments[index]); + if (!isFinite(codePoint) || codePoint < 0 || codePoint > 1114111 || floor(codePoint) !== codePoint) throw RangeError("Invalid code point: " + codePoint); + if (codePoint <= 65535) codeUnits.push(codePoint); + else { + codePoint -= 65536; + highSurrogate = (codePoint >> 10) + 55296; + lowSurrogate = codePoint % 1024 + 56320; + codeUnits.push(highSurrogate, lowSurrogate); + } + if (index + 1 === length || codeUnits.length > MAX_SIZE) { + result += stringFromCharCode.apply(null, codeUnits); + codeUnits.length = 0; + } + } + return result; + }; + /* istanbul ignore next */ + if (Object.defineProperty) Object.defineProperty(String, "fromCodePoint", { + value: fromCodePoint, + configurable: true, + writable: true + }); + else String.fromCodePoint = fromCodePoint; + })(); + return sax$1; }; +const sax = initializeSax(); -//#endregion - -//# sourceMappingURL=functional.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/index.js - - - - - - -//#region src/structured_query/index.ts -var structured_query_exports = {}; -__export(structured_query_exports, { - BaseTranslator: () => BaseTranslator, - BasicTranslator: () => BasicTranslator, - Comparators: () => Comparators, - Comparison: () => Comparison, - Expression: () => Expression, - FilterDirective: () => FilterDirective, - FunctionalTranslator: () => FunctionalTranslator, - Operation: () => Operation, - Operators: () => Operators, - StructuredQuery: () => StructuredQuery, - Visitor: () => Visitor, - castValue: () => castValue, - isBoolean: () => isBoolean, - isFilterEmpty: () => isFilterEmpty, - isFloat: () => isFloat, - isInt: () => isInt, - isObject: () => isObject, - isString: () => isString -}); - -//#endregion - -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/checks.js - - -;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/iso.js - - -const ZodISODateTime = /*@__PURE__*/ $constructor("ZodISODateTime", (inst, def) => { - $ZodISODateTime.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function iso_datetime(params) { - return _isoDateTime(ZodISODateTime, params); -} -const ZodISODate = /*@__PURE__*/ $constructor("ZodISODate", (inst, def) => { - $ZodISODate.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function iso_date(params) { - return _isoDate(ZodISODate, params); -} -const ZodISOTime = /*@__PURE__*/ $constructor("ZodISOTime", (inst, def) => { - $ZodISOTime.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function iso_time(params) { - return _isoTime(ZodISOTime, params); -} -const ZodISODuration = /*@__PURE__*/ $constructor("ZodISODuration", (inst, def) => { - $ZodISODuration.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function iso_duration(params) { - return _isoDuration(ZodISODuration, params); -} - -;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/errors.js - - - -const errors_initializer = (inst, issues) => { - $ZodError.init(inst, issues); - inst.name = "ZodError"; - Object.defineProperties(inst, { - format: { - value: (mapper) => formatError(inst, mapper), - // enumerable: false, - }, - flatten: { - value: (mapper) => flattenError(inst, mapper), - // enumerable: false, - }, - addIssue: { - value: (issue) => { - inst.issues.push(issue); - inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); - }, - // enumerable: false, - }, - addIssues: { - value: (issues) => { - inst.issues.push(...issues); - inst.message = JSON.stringify(inst.issues, jsonStringifyReplacer, 2); - }, - // enumerable: false, - }, - isEmpty: { - get() { - return inst.issues.length === 0; - }, - // enumerable: false, - }, - }); - // Object.defineProperty(inst, "isEmpty", { - // get() { - // return inst.issues.length === 0; - // }, - // }); -}; -const errors_ZodError = $constructor("ZodError", errors_initializer); -const ZodRealError = $constructor("ZodError", errors_initializer, { - Parent: Error, -}); -// /** @deprecated Use `z.core.$ZodErrorMapCtx` instead. */ -// export type ErrorMapCtx = core.$ZodErrorMapCtx; - -;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/parse.js - - -const classic_parse_parse = /* @__PURE__ */ _parse(ZodRealError); -const parse_parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError); -const parse_safeParse = /* @__PURE__ */ _safeParse(ZodRealError); -const parse_safeParseAsync = /* @__PURE__ */ _safeParseAsync(ZodRealError); -// Codec functions -const parse_encode = /* @__PURE__ */ _encode(ZodRealError); -const parse_decode = /* @__PURE__ */ _decode(ZodRealError); -const parse_encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError); -const parse_decodeAsync = /* @__PURE__ */ _decodeAsync(ZodRealError); -const parse_safeEncode = /* @__PURE__ */ _safeEncode(ZodRealError); -const parse_safeDecode = /* @__PURE__ */ _safeDecode(ZodRealError); -const parse_safeEncodeAsync = /* @__PURE__ */ _safeEncodeAsync(ZodRealError); -const parse_safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync(ZodRealError); - -;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/schemas.js - - - - - -const schemas_ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => { - $ZodType.init(inst, def); - inst.def = def; - inst.type = def.type; - Object.defineProperty(inst, "_def", { value: def }); - // base methods - inst.check = (...checks) => { - return inst.clone(mergeDefs(def, { - checks: [ - ...(def.checks ?? []), - ...checks.map((ch) => typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch), - ], - })); - }; - inst.clone = (def, params) => clone(inst, def, params); - inst.brand = () => inst; - inst.register = ((reg, meta) => { - reg.add(inst, meta); - return inst; - }); - // parsing - inst.parse = (data, params) => classic_parse_parse(inst, data, params, { callee: inst.parse }); - inst.safeParse = (data, params) => parse_safeParse(inst, data, params); - inst.parseAsync = async (data, params) => parse_parseAsync(inst, data, params, { callee: inst.parseAsync }); - inst.safeParseAsync = async (data, params) => parse_safeParseAsync(inst, data, params); - inst.spa = inst.safeParseAsync; - // encoding/decoding - inst.encode = (data, params) => parse_encode(inst, data, params); - inst.decode = (data, params) => parse_decode(inst, data, params); - inst.encodeAsync = async (data, params) => parse_encodeAsync(inst, data, params); - inst.decodeAsync = async (data, params) => parse_decodeAsync(inst, data, params); - inst.safeEncode = (data, params) => parse_safeEncode(inst, data, params); - inst.safeDecode = (data, params) => parse_safeDecode(inst, data, params); - inst.safeEncodeAsync = async (data, params) => parse_safeEncodeAsync(inst, data, params); - inst.safeDecodeAsync = async (data, params) => parse_safeDecodeAsync(inst, data, params); - // refinements - inst.refine = (check, params) => inst.check(refine(check, params)); - inst.superRefine = (refinement) => inst.check(superRefine(refinement)); - inst.overwrite = (fn) => inst.check(_overwrite(fn)); - // wrappers - inst.optional = () => optional(inst); - inst.nullable = () => nullable(inst); - inst.nullish = () => optional(nullable(inst)); - inst.nonoptional = (params) => nonoptional(inst, params); - inst.array = () => array(inst); - inst.or = (arg) => union([inst, arg]); - inst.and = (arg) => intersection(inst, arg); - inst.transform = (tx) => pipe(inst, transform(tx)); - inst.default = (def) => schemas_default(inst, def); - inst.prefault = (def) => prefault(inst, def); - // inst.coalesce = (def, params) => coalesce(inst, def, params); - inst.catch = (params) => schemas_catch(inst, params); - inst.pipe = (target) => pipe(inst, target); - inst.readonly = () => readonly(inst); - // meta - inst.describe = (description) => { - const cl = inst.clone(); - globalRegistry.add(cl, { description }); - return cl; - }; - Object.defineProperty(inst, "description", { - get() { - return globalRegistry.get(inst)?.description; - }, - configurable: true, - }); - inst.meta = (...args) => { - if (args.length === 0) { - return globalRegistry.get(inst); - } - const cl = inst.clone(); - globalRegistry.add(cl, args[0]); - return cl; - }; - // helpers - inst.isOptional = () => inst.safeParse(undefined).success; - inst.isNullable = () => inst.safeParse(null).success; - return inst; -}); -/** @internal */ -const _ZodString = /*@__PURE__*/ $constructor("_ZodString", (inst, def) => { - $ZodString.init(inst, def); - schemas_ZodType.init(inst, def); - const bag = inst._zod.bag; - inst.format = bag.format ?? null; - inst.minLength = bag.minimum ?? null; - inst.maxLength = bag.maximum ?? null; - // validations - inst.regex = (...args) => inst.check(_regex(...args)); - inst.includes = (...args) => inst.check(_includes(...args)); - inst.startsWith = (...args) => inst.check(_startsWith(...args)); - inst.endsWith = (...args) => inst.check(_endsWith(...args)); - inst.min = (...args) => inst.check(_minLength(...args)); - inst.max = (...args) => inst.check(_maxLength(...args)); - inst.length = (...args) => inst.check(_length(...args)); - inst.nonempty = (...args) => inst.check(_minLength(1, ...args)); - inst.lowercase = (params) => inst.check(_lowercase(params)); - inst.uppercase = (params) => inst.check(_uppercase(params)); - // transforms - inst.trim = () => inst.check(_trim()); - inst.normalize = (...args) => inst.check(_normalize(...args)); - inst.toLowerCase = () => inst.check(_toLowerCase()); - inst.toUpperCase = () => inst.check(_toUpperCase()); - inst.slugify = () => inst.check(_slugify()); -}); -const schemas_ZodString = /*@__PURE__*/ $constructor("ZodString", (inst, def) => { - $ZodString.init(inst, def); - _ZodString.init(inst, def); - inst.email = (params) => inst.check(_email(ZodEmail, params)); - inst.url = (params) => inst.check(_url(ZodURL, params)); - inst.jwt = (params) => inst.check(_jwt(ZodJWT, params)); - inst.emoji = (params) => inst.check(api_emoji(ZodEmoji, params)); - inst.guid = (params) => inst.check(_guid(ZodGUID, params)); - inst.uuid = (params) => inst.check(_uuid(ZodUUID, params)); - inst.uuidv4 = (params) => inst.check(_uuidv4(ZodUUID, params)); - inst.uuidv6 = (params) => inst.check(_uuidv6(ZodUUID, params)); - inst.uuidv7 = (params) => inst.check(_uuidv7(ZodUUID, params)); - inst.nanoid = (params) => inst.check(_nanoid(ZodNanoID, params)); - inst.guid = (params) => inst.check(_guid(ZodGUID, params)); - inst.cuid = (params) => inst.check(_cuid(ZodCUID, params)); - inst.cuid2 = (params) => inst.check(_cuid2(ZodCUID2, params)); - inst.ulid = (params) => inst.check(_ulid(ZodULID, params)); - inst.base64 = (params) => inst.check(_base64(ZodBase64, params)); - inst.base64url = (params) => inst.check(_base64url(ZodBase64URL, params)); - inst.xid = (params) => inst.check(_xid(ZodXID, params)); - inst.ksuid = (params) => inst.check(_ksuid(ZodKSUID, params)); - inst.ipv4 = (params) => inst.check(_ipv4(ZodIPv4, params)); - inst.ipv6 = (params) => inst.check(_ipv6(ZodIPv6, params)); - inst.cidrv4 = (params) => inst.check(_cidrv4(ZodCIDRv4, params)); - inst.cidrv6 = (params) => inst.check(_cidrv6(ZodCIDRv6, params)); - inst.e164 = (params) => inst.check(_e164(ZodE164, params)); - // iso - inst.datetime = (params) => inst.check(iso_datetime(params)); - inst.date = (params) => inst.check(iso_date(params)); - inst.time = (params) => inst.check(iso_time(params)); - inst.duration = (params) => inst.check(iso_duration(params)); -}); -function schemas_string(params) { - return _string(schemas_ZodString, params); -} -const ZodStringFormat = /*@__PURE__*/ $constructor("ZodStringFormat", (inst, def) => { - $ZodStringFormat.init(inst, def); - _ZodString.init(inst, def); -}); -const ZodEmail = /*@__PURE__*/ $constructor("ZodEmail", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodEmail.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_email(params) { - return _email(ZodEmail, params); -} -const ZodGUID = /*@__PURE__*/ $constructor("ZodGUID", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodGUID.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_guid(params) { - return _guid(ZodGUID, params); -} -const ZodUUID = /*@__PURE__*/ $constructor("ZodUUID", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodUUID.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_uuid(params) { - return _uuid(ZodUUID, params); -} -function uuidv4(params) { - return _uuidv4(ZodUUID, params); -} -// ZodUUIDv6 -function uuidv6(params) { - return _uuidv6(ZodUUID, params); -} -// ZodUUIDv7 -function schemas_uuidv7(params) { - return _uuidv7(ZodUUID, params); -} -const ZodURL = /*@__PURE__*/ $constructor("ZodURL", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodURL.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function url(params) { - return _url(ZodURL, params); -} -function httpUrl(params) { - return _url(ZodURL, { - protocol: /^https?$/, - hostname: domain, - ...normalizeParams(params), - }); -} -const ZodEmoji = /*@__PURE__*/ $constructor("ZodEmoji", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodEmoji.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_emoji(params) { - return api_emoji(ZodEmoji, params); -} -const ZodNanoID = /*@__PURE__*/ $constructor("ZodNanoID", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodNanoID.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_nanoid(params) { - return _nanoid(ZodNanoID, params); -} -const ZodCUID = /*@__PURE__*/ $constructor("ZodCUID", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodCUID.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_cuid(params) { - return _cuid(ZodCUID, params); -} -const ZodCUID2 = /*@__PURE__*/ $constructor("ZodCUID2", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodCUID2.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_cuid2(params) { - return _cuid2(ZodCUID2, params); -} -const ZodULID = /*@__PURE__*/ $constructor("ZodULID", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodULID.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_ulid(params) { - return _ulid(ZodULID, params); -} -const ZodXID = /*@__PURE__*/ $constructor("ZodXID", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodXID.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_xid(params) { - return _xid(ZodXID, params); -} -const ZodKSUID = /*@__PURE__*/ $constructor("ZodKSUID", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodKSUID.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_ksuid(params) { - return _ksuid(ZodKSUID, params); -} -const ZodIPv4 = /*@__PURE__*/ $constructor("ZodIPv4", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodIPv4.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_ipv4(params) { - return _ipv4(ZodIPv4, params); -} -const ZodMAC = /*@__PURE__*/ $constructor("ZodMAC", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodMAC.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_mac(params) { - return _mac(ZodMAC, params); -} -const ZodIPv6 = /*@__PURE__*/ $constructor("ZodIPv6", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodIPv6.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_ipv6(params) { - return _ipv6(ZodIPv6, params); -} -const ZodCIDRv4 = /*@__PURE__*/ $constructor("ZodCIDRv4", (inst, def) => { - $ZodCIDRv4.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_cidrv4(params) { - return _cidrv4(ZodCIDRv4, params); -} -const ZodCIDRv6 = /*@__PURE__*/ $constructor("ZodCIDRv6", (inst, def) => { - $ZodCIDRv6.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_cidrv6(params) { - return _cidrv6(ZodCIDRv6, params); -} -const ZodBase64 = /*@__PURE__*/ $constructor("ZodBase64", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodBase64.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_base64(params) { - return _base64(ZodBase64, params); -} -const ZodBase64URL = /*@__PURE__*/ $constructor("ZodBase64URL", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodBase64URL.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_base64url(params) { - return _base64url(ZodBase64URL, params); -} -const ZodE164 = /*@__PURE__*/ $constructor("ZodE164", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodE164.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function schemas_e164(params) { - return _e164(ZodE164, params); -} -const ZodJWT = /*@__PURE__*/ $constructor("ZodJWT", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodJWT.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function jwt(params) { - return _jwt(ZodJWT, params); -} -const ZodCustomStringFormat = /*@__PURE__*/ $constructor("ZodCustomStringFormat", (inst, def) => { - // ZodStringFormat.init(inst, def); - $ZodCustomStringFormat.init(inst, def); - ZodStringFormat.init(inst, def); -}); -function stringFormat(format, fnOrRegex, _params = {}) { - return _stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params); -} -function schemas_hostname(_params) { - return _stringFormat(ZodCustomStringFormat, "hostname", hostname, _params); -} -function schemas_hex(_params) { - return _stringFormat(ZodCustomStringFormat, "hex", hex, _params); -} -function hash(alg, params) { - const enc = params?.enc ?? "hex"; - const format = `${alg}_${enc}`; - const regex = regexes_namespaceObject[format]; - if (!regex) - throw new Error(`Unrecognized hash format: ${format}`); - return _stringFormat(ZodCustomStringFormat, format, regex, params); -} -const schemas_ZodNumber = /*@__PURE__*/ $constructor("ZodNumber", (inst, def) => { - $ZodNumber.init(inst, def); - schemas_ZodType.init(inst, def); - inst.gt = (value, params) => inst.check(_gt(value, params)); - inst.gte = (value, params) => inst.check(_gte(value, params)); - inst.min = (value, params) => inst.check(_gte(value, params)); - inst.lt = (value, params) => inst.check(_lt(value, params)); - inst.lte = (value, params) => inst.check(_lte(value, params)); - inst.max = (value, params) => inst.check(_lte(value, params)); - inst.int = (params) => inst.check(schemas_int(params)); - inst.safe = (params) => inst.check(schemas_int(params)); - inst.positive = (params) => inst.check(_gt(0, params)); - inst.nonnegative = (params) => inst.check(_gte(0, params)); - inst.negative = (params) => inst.check(_lt(0, params)); - inst.nonpositive = (params) => inst.check(_lte(0, params)); - inst.multipleOf = (value, params) => inst.check(_multipleOf(value, params)); - inst.step = (value, params) => inst.check(_multipleOf(value, params)); - // inst.finite = (params) => inst.check(core.finite(params)); - inst.finite = () => inst; - const bag = inst._zod.bag; - inst.minValue = - Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; - inst.maxValue = - Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; - inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? 0.5); - inst.isFinite = true; - inst.format = bag.format ?? null; -}); -function schemas_number(params) { - return _number(schemas_ZodNumber, params); -} -const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def) => { - $ZodNumberFormat.init(inst, def); - schemas_ZodNumber.init(inst, def); -}); -function schemas_int(params) { - return _int(ZodNumberFormat, params); -} -function float32(params) { - return _float32(ZodNumberFormat, params); -} -function float64(params) { - return _float64(ZodNumberFormat, params); -} -function int32(params) { - return _int32(ZodNumberFormat, params); -} -function uint32(params) { - return _uint32(ZodNumberFormat, params); -} -const schemas_ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => { - $ZodBoolean.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function schemas_boolean(params) { - return _boolean(schemas_ZodBoolean, params); -} -const schemas_ZodBigInt = /*@__PURE__*/ $constructor("ZodBigInt", (inst, def) => { - $ZodBigInt.init(inst, def); - schemas_ZodType.init(inst, def); - inst.gte = (value, params) => inst.check(_gte(value, params)); - inst.min = (value, params) => inst.check(_gte(value, params)); - inst.gt = (value, params) => inst.check(_gt(value, params)); - inst.gte = (value, params) => inst.check(_gte(value, params)); - inst.min = (value, params) => inst.check(_gte(value, params)); - inst.lt = (value, params) => inst.check(_lt(value, params)); - inst.lte = (value, params) => inst.check(_lte(value, params)); - inst.max = (value, params) => inst.check(_lte(value, params)); - inst.positive = (params) => inst.check(_gt(BigInt(0), params)); - inst.negative = (params) => inst.check(_lt(BigInt(0), params)); - inst.nonpositive = (params) => inst.check(_lte(BigInt(0), params)); - inst.nonnegative = (params) => inst.check(_gte(BigInt(0), params)); - inst.multipleOf = (value, params) => inst.check(_multipleOf(value, params)); - const bag = inst._zod.bag; - inst.minValue = bag.minimum ?? null; - inst.maxValue = bag.maximum ?? null; - inst.format = bag.format ?? null; -}); -function schemas_bigint(params) { - return _bigint(schemas_ZodBigInt, params); -} -const ZodBigIntFormat = /*@__PURE__*/ $constructor("ZodBigIntFormat", (inst, def) => { - $ZodBigIntFormat.init(inst, def); - schemas_ZodBigInt.init(inst, def); -}); -// int64 -function int64(params) { - return _int64(ZodBigIntFormat, params); -} -// uint64 -function uint64(params) { - return _uint64(ZodBigIntFormat, params); -} -const schemas_ZodSymbol = /*@__PURE__*/ $constructor("ZodSymbol", (inst, def) => { - $ZodSymbol.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function symbol(params) { - return _symbol(schemas_ZodSymbol, params); -} -const schemas_ZodUndefined = /*@__PURE__*/ $constructor("ZodUndefined", (inst, def) => { - $ZodUndefined.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function schemas_undefined(params) { - return api_undefined(schemas_ZodUndefined, params); -} - -const schemas_ZodNull = /*@__PURE__*/ $constructor("ZodNull", (inst, def) => { - $ZodNull.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function schemas_null(params) { - return api_null(schemas_ZodNull, params); -} +//#endregion -const schemas_ZodAny = /*@__PURE__*/ $constructor("ZodAny", (inst, def) => { - $ZodAny.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function any() { - return _any(schemas_ZodAny); -} -const schemas_ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => { - $ZodUnknown.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function unknown() { - return _unknown(schemas_ZodUnknown); -} -const schemas_ZodNever = /*@__PURE__*/ $constructor("ZodNever", (inst, def) => { - $ZodNever.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function schemas_never(params) { - return _never(schemas_ZodNever, params); -} -const schemas_ZodVoid = /*@__PURE__*/ $constructor("ZodVoid", (inst, def) => { - $ZodVoid.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function schemas_void(params) { - return _void(schemas_ZodVoid, params); -} +//# sourceMappingURL=sax.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/xml.js -const schemas_ZodDate = /*@__PURE__*/ $constructor("ZodDate", (inst, def) => { - $ZodDate.init(inst, def); - schemas_ZodType.init(inst, def); - inst.min = (value, params) => inst.check(_gte(value, params)); - inst.max = (value, params) => inst.check(_lte(value, params)); - const c = inst._zod.bag; - inst.minDate = c.minimum ? new Date(c.minimum) : null; - inst.maxDate = c.maximum ? new Date(c.maximum) : null; -}); -function schemas_date(params) { - return _date(schemas_ZodDate, params); -} -const schemas_ZodArray = /*@__PURE__*/ $constructor("ZodArray", (inst, def) => { - $ZodArray.init(inst, def); - schemas_ZodType.init(inst, def); - inst.element = def.element; - inst.min = (minLength, params) => inst.check(_minLength(minLength, params)); - inst.nonempty = (params) => inst.check(_minLength(1, params)); - inst.max = (maxLength, params) => inst.check(_maxLength(maxLength, params)); - inst.length = (len, params) => inst.check(_length(len, params)); - inst.unwrap = () => inst.element; -}); -function array(element, params) { - return _array(schemas_ZodArray, element, params); -} -// .keyof -function keyof(schema) { - const shape = schema._zod.def.shape; - return schemas_enum(Object.keys(shape)); -} -const schemas_ZodObject = /*@__PURE__*/ $constructor("ZodObject", (inst, def) => { - $ZodObjectJIT.init(inst, def); - schemas_ZodType.init(inst, def); - defineLazy(inst, "shape", () => { - return def.shape; - }); - inst.keyof = () => schemas_enum(Object.keys(inst._zod.def.shape)); - inst.catchall = (catchall) => inst.clone({ ...inst._zod.def, catchall: catchall }); - inst.passthrough = () => inst.clone({ ...inst._zod.def, catchall: unknown() }); - inst.loose = () => inst.clone({ ...inst._zod.def, catchall: unknown() }); - inst.strict = () => inst.clone({ ...inst._zod.def, catchall: schemas_never() }); - inst.strip = () => inst.clone({ ...inst._zod.def, catchall: undefined }); - inst.extend = (incoming) => { - return extend(inst, incoming); - }; - inst.safeExtend = (incoming) => { - return safeExtend(inst, incoming); - }; - inst.merge = (other) => merge(inst, other); - inst.pick = (mask) => pick(inst, mask); - inst.omit = (mask) => omit(inst, mask); - inst.partial = (...args) => partial(schemas_ZodOptional, inst, args[0]); - inst.required = (...args) => required(ZodNonOptional, inst, args[0]); -}); -function object(shape, params) { - const def = { - type: "object", - shape: shape ?? {}, - ...normalizeParams(params), - }; - return new schemas_ZodObject(def); -} -// strictObject -function strictObject(shape, params) { - return new schemas_ZodObject({ - type: "object", - shape, - catchall: schemas_never(), - ...normalizeParams(params), - }); -} -// looseObject -function looseObject(shape, params) { - return new schemas_ZodObject({ - type: "object", - shape, - catchall: unknown(), - ...normalizeParams(params), - }); -} -const schemas_ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => { - $ZodUnion.init(inst, def); - schemas_ZodType.init(inst, def); - inst.options = def.options; -}); -function union(options, params) { - return new schemas_ZodUnion({ - type: "union", - options: options, - ...normalizeParams(params), - }); -} -const schemas_ZodDiscriminatedUnion = /*@__PURE__*/ $constructor("ZodDiscriminatedUnion", (inst, def) => { - schemas_ZodUnion.init(inst, def); - $ZodDiscriminatedUnion.init(inst, def); -}); -function discriminatedUnion(discriminator, options, params) { - // const [options, params] = args; - return new schemas_ZodDiscriminatedUnion({ - type: "union", - options, - discriminator, - ...normalizeParams(params), - }); -} -const schemas_ZodIntersection = /*@__PURE__*/ $constructor("ZodIntersection", (inst, def) => { - $ZodIntersection.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function intersection(left, right) { - return new schemas_ZodIntersection({ - type: "intersection", - left: left, - right: right, - }); -} -const schemas_ZodTuple = /*@__PURE__*/ $constructor("ZodTuple", (inst, def) => { - $ZodTuple.init(inst, def); - schemas_ZodType.init(inst, def); - inst.rest = (rest) => inst.clone({ - ...inst._zod.def, - rest: rest, - }); -}); -function tuple(items, _paramsOrRest, _params) { - const hasRest = _paramsOrRest instanceof $ZodType; - const params = hasRest ? _params : _paramsOrRest; - const rest = hasRest ? _paramsOrRest : null; - return new schemas_ZodTuple({ - type: "tuple", - items: items, - rest, - ...normalizeParams(params), - }); -} -const schemas_ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => { - $ZodRecord.init(inst, def); - schemas_ZodType.init(inst, def); - inst.keyType = def.keyType; - inst.valueType = def.valueType; -}); -function record(keyType, valueType, params) { - return new schemas_ZodRecord({ - type: "record", - keyType, - valueType: valueType, - ...normalizeParams(params), - }); -} -// type alksjf = core.output; -function partialRecord(keyType, valueType, params) { - const k = clone(keyType); - k._zod.values = undefined; - return new schemas_ZodRecord({ - type: "record", - keyType: k, - valueType: valueType, - ...normalizeParams(params), - }); -} -const schemas_ZodMap = /*@__PURE__*/ $constructor("ZodMap", (inst, def) => { - $ZodMap.init(inst, def); - schemas_ZodType.init(inst, def); - inst.keyType = def.keyType; - inst.valueType = def.valueType; -}); -function map(keyType, valueType, params) { - return new schemas_ZodMap({ - type: "map", - keyType: keyType, - valueType: valueType, - ...normalizeParams(params), - }); -} -const schemas_ZodSet = /*@__PURE__*/ $constructor("ZodSet", (inst, def) => { - $ZodSet.init(inst, def); - schemas_ZodType.init(inst, def); - inst.min = (...args) => inst.check(_minSize(...args)); - inst.nonempty = (params) => inst.check(_minSize(1, params)); - inst.max = (...args) => inst.check(_maxSize(...args)); - inst.size = (...args) => inst.check(_size(...args)); -}); -function set(valueType, params) { - return new schemas_ZodSet({ - type: "set", - valueType: valueType, - ...normalizeParams(params), - }); -} -const schemas_ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => { - $ZodEnum.init(inst, def); - schemas_ZodType.init(inst, def); - inst.enum = def.entries; - inst.options = Object.values(def.entries); - const keys = new Set(Object.keys(def.entries)); - inst.extract = (values, params) => { - const newEntries = {}; - for (const value of values) { - if (keys.has(value)) { - newEntries[value] = def.entries[value]; - } - else - throw new Error(`Key ${value} not found in enum`); - } - return new schemas_ZodEnum({ - ...def, - checks: [], - ...normalizeParams(params), - entries: newEntries, - }); - }; - inst.exclude = (values, params) => { - const newEntries = { ...def.entries }; - for (const value of values) { - if (keys.has(value)) { - delete newEntries[value]; - } - else - throw new Error(`Key ${value} not found in enum`); - } - return new schemas_ZodEnum({ - ...def, - checks: [], - ...normalizeParams(params), - entries: newEntries, - }); - }; -}); -function schemas_enum(values, params) { - const entries = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values; - return new schemas_ZodEnum({ - type: "enum", - entries, - ...normalizeParams(params), - }); -} -/** @deprecated This API has been merged into `z.enum()`. Use `z.enum()` instead. - * - * ```ts - * enum Colors { red, green, blue } - * z.enum(Colors); - * ``` - */ -function nativeEnum(entries, params) { - return new schemas_ZodEnum({ - type: "enum", - entries, - ...normalizeParams(params), - }); -} -const schemas_ZodLiteral = /*@__PURE__*/ $constructor("ZodLiteral", (inst, def) => { - $ZodLiteral.init(inst, def); - schemas_ZodType.init(inst, def); - inst.values = new Set(def.values); - Object.defineProperty(inst, "value", { - get() { - if (def.values.length > 1) { - throw new Error("This schema contains multiple valid literal values. Use `.values` instead."); - } - return def.values[0]; - }, - }); -}); -function literal(value, params) { - return new schemas_ZodLiteral({ - type: "literal", - values: Array.isArray(value) ? value : [value], - ...normalizeParams(params), - }); -} -const ZodFile = /*@__PURE__*/ $constructor("ZodFile", (inst, def) => { - $ZodFile.init(inst, def); - schemas_ZodType.init(inst, def); - inst.min = (size, params) => inst.check(_minSize(size, params)); - inst.max = (size, params) => inst.check(_maxSize(size, params)); - inst.mime = (types, params) => inst.check(_mime(Array.isArray(types) ? types : [types], params)); -}); -function file(params) { - return _file(ZodFile, params); -} -const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => { - $ZodTransform.init(inst, def); - schemas_ZodType.init(inst, def); - inst._zod.parse = (payload, _ctx) => { - if (_ctx.direction === "backward") { - throw new $ZodEncodeError(inst.constructor.name); - } - payload.addIssue = (issue) => { - if (typeof issue === "string") { - payload.issues.push(util_issue(issue, payload.value, def)); - } - else { - // for Zod 3 backwards compatibility - const _issue = issue; - if (_issue.fatal) - _issue.continue = false; - _issue.code ?? (_issue.code = "custom"); - _issue.input ?? (_issue.input = payload.value); - _issue.inst ?? (_issue.inst = inst); - // _issue.continue ??= true; - payload.issues.push(util_issue(_issue)); - } - }; - const output = def.transform(payload.value, payload); - if (output instanceof Promise) { - return output.then((output) => { - payload.value = output; - return payload; - }); - } - payload.value = output; - return payload; - }; -}); -function transform(fn) { - return new ZodTransform({ - type: "transform", - transform: fn, - }); -} -const schemas_ZodOptional = /*@__PURE__*/ $constructor("ZodOptional", (inst, def) => { - $ZodOptional.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.innerType; -}); -function optional(innerType) { - return new schemas_ZodOptional({ - type: "optional", - innerType: innerType, - }); -} -const schemas_ZodNullable = /*@__PURE__*/ $constructor("ZodNullable", (inst, def) => { - $ZodNullable.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.innerType; -}); -function nullable(innerType) { - return new schemas_ZodNullable({ - type: "nullable", - innerType: innerType, - }); -} -// nullish -function schemas_nullish(innerType) { - return optional(nullable(innerType)); -} -const schemas_ZodDefault = /*@__PURE__*/ $constructor("ZodDefault", (inst, def) => { - $ZodDefault.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.innerType; - inst.removeDefault = inst.unwrap; -}); -function schemas_default(innerType, defaultValue) { - return new schemas_ZodDefault({ - type: "default", - innerType: innerType, - get defaultValue() { - return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); - }, - }); -} -const ZodPrefault = /*@__PURE__*/ $constructor("ZodPrefault", (inst, def) => { - $ZodPrefault.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.innerType; -}); -function prefault(innerType, defaultValue) { - return new ZodPrefault({ - type: "prefault", - innerType: innerType, - get defaultValue() { - return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue); - }, - }); -} -const ZodNonOptional = /*@__PURE__*/ $constructor("ZodNonOptional", (inst, def) => { - $ZodNonOptional.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.innerType; -}); -function nonoptional(innerType, params) { - return new ZodNonOptional({ - type: "nonoptional", - innerType: innerType, - ...normalizeParams(params), - }); -} -const ZodSuccess = /*@__PURE__*/ $constructor("ZodSuccess", (inst, def) => { - $ZodSuccess.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.innerType; -}); -function success(innerType) { - return new ZodSuccess({ - type: "success", - innerType: innerType, - }); -} -const schemas_ZodCatch = /*@__PURE__*/ $constructor("ZodCatch", (inst, def) => { - $ZodCatch.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.innerType; - inst.removeCatch = inst.unwrap; -}); -function schemas_catch(innerType, catchValue) { - return new schemas_ZodCatch({ - type: "catch", - innerType: innerType, - catchValue: (typeof catchValue === "function" ? catchValue : () => catchValue), - }); -} -const schemas_ZodNaN = /*@__PURE__*/ $constructor("ZodNaN", (inst, def) => { - $ZodNaN.init(inst, def); - schemas_ZodType.init(inst, def); -}); -function nan(params) { - return _nan(schemas_ZodNaN, params); -} -const ZodPipe = /*@__PURE__*/ $constructor("ZodPipe", (inst, def) => { - $ZodPipe.init(inst, def); - schemas_ZodType.init(inst, def); - inst.in = def.in; - inst.out = def.out; -}); -function pipe(in_, out) { - return new ZodPipe({ - type: "pipe", - in: in_, - out: out, - // ...util.normalizeParams(params), - }); -} -const ZodCodec = /*@__PURE__*/ $constructor("ZodCodec", (inst, def) => { - ZodPipe.init(inst, def); - $ZodCodec.init(inst, def); -}); -function codec(in_, out, params) { - return new ZodCodec({ - type: "pipe", - in: in_, - out: out, - transform: params.decode, - reverseTransform: params.encode, - }); + + +//#region src/output_parsers/xml.ts +const XML_FORMAT_INSTRUCTIONS = `The output should be formatted as a XML file. +1. Output should conform to the tags below. +2. If tags are not given, make them on your own. +3. Remember to always open and close all the tags. + +As an example, for the tags ["foo", "bar", "baz"]: +1. String "\n \n \n \n" is a well-formatted instance of the schema. +2. String "\n \n " is a badly-formatted instance. +3. String "\n \n \n" is a badly-formatted instance. + +Here are the output tags: +\`\`\` +{tags} +\`\`\``; +var XMLOutputParser = class extends BaseCumulativeTransformOutputParser { + tags; + constructor(fields) { + super(fields); + this.tags = fields?.tags; + } + static lc_name() { + return "XMLOutputParser"; + } + lc_namespace = ["langchain_core", "output_parsers"]; + lc_serializable = true; + _diff(prev, next) { + if (!next) return void 0; + if (!prev) return [{ + op: "replace", + path: "", + value: next + }]; + return compare(prev, next); + } + async parsePartialResult(generations) { + return parseXMLMarkdown(generations[0].text); + } + async parse(text) { + return parseXMLMarkdown(text); + } + getFormatInstructions() { + const withTags = !!(this.tags && this.tags.length > 0); + return withTags ? XML_FORMAT_INSTRUCTIONS.replace("{tags}", this.tags?.join(", ") ?? "") : XML_FORMAT_INSTRUCTIONS; + } +}; +const strip = (text) => text.split("\n").map((line) => line.replace(/^\s+/, "")).join("\n").trim(); +const parseParsedResult = (input) => { + if (Object.keys(input).length === 0) return {}; + const result = {}; + if (input.children.length > 0) { + result[input.name] = input.children.map(parseParsedResult); + return result; + } else { + result[input.name] = input.text ?? void 0; + return result; + } +}; +function parseXMLMarkdown(s) { + const cleanedString = strip(s); + const parser = sax.parser(true); + let parsedResult = {}; + const elementStack = []; + parser.onopentag = (node) => { + const element = { + name: node.name, + attributes: node.attributes, + children: [], + text: "", + isSelfClosing: node.isSelfClosing + }; + if (elementStack.length > 0) { + const parentElement = elementStack[elementStack.length - 1]; + parentElement.children.push(element); + } else parsedResult = element; + if (!node.isSelfClosing) elementStack.push(element); + }; + parser.onclosetag = () => { + if (elementStack.length > 0) { + const lastElement = elementStack.pop(); + if (elementStack.length === 0 && lastElement) parsedResult = lastElement; + } + }; + parser.ontext = (text) => { + if (elementStack.length > 0) { + const currentElement = elementStack[elementStack.length - 1]; + currentElement.text += text; + } + }; + parser.onattribute = (attr) => { + if (elementStack.length > 0) { + const currentElement = elementStack[elementStack.length - 1]; + currentElement.attributes[attr.name] = attr.value; + } + }; + const match = /```(xml)?(.*)```/s.exec(cleanedString); + const xmlString = match ? match[2] : cleanedString; + parser.write(xmlString).close(); + if (parsedResult && parsedResult.name === "?xml") parsedResult = parsedResult.children[0]; + return parseParsedResult(parsedResult); } -const schemas_ZodReadonly = /*@__PURE__*/ $constructor("ZodReadonly", (inst, def) => { - $ZodReadonly.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.innerType; + +//#endregion + +//# sourceMappingURL=xml.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/index.js + + + + + + + + + + + +//#region src/output_parsers/index.ts +var output_parsers_exports = {}; +__export(output_parsers_exports, { + AsymmetricStructuredOutputParser: () => AsymmetricStructuredOutputParser, + BaseCumulativeTransformOutputParser: () => BaseCumulativeTransformOutputParser, + BaseLLMOutputParser: () => BaseLLMOutputParser, + BaseOutputParser: () => BaseOutputParser, + BaseTransformOutputParser: () => BaseTransformOutputParser, + BytesOutputParser: () => BytesOutputParser, + CommaSeparatedListOutputParser: () => CommaSeparatedListOutputParser, + CustomListOutputParser: () => CustomListOutputParser, + JsonMarkdownStructuredOutputParser: () => JsonMarkdownStructuredOutputParser, + JsonOutputParser: () => JsonOutputParser, + ListOutputParser: () => ListOutputParser, + MarkdownListOutputParser: () => MarkdownListOutputParser, + NumberedListOutputParser: () => NumberedListOutputParser, + OutputParserException: () => OutputParserException, + StringOutputParser: () => StringOutputParser, + StructuredOutputParser: () => StructuredOutputParser, + XMLOutputParser: () => XMLOutputParser, + XML_FORMAT_INSTRUCTIONS: () => XML_FORMAT_INSTRUCTIONS, + parseJsonMarkdown: () => parseJsonMarkdown, + parsePartialJson: () => parsePartialJson, + parseXMLMarkdown: () => parseXMLMarkdown }); -function readonly(innerType) { - return new schemas_ZodReadonly({ - type: "readonly", - innerType: innerType, - }); -} -const ZodTemplateLiteral = /*@__PURE__*/ $constructor("ZodTemplateLiteral", (inst, def) => { - $ZodTemplateLiteral.init(inst, def); - schemas_ZodType.init(inst, def); + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/openai_functions/json_output_functions_parsers.js + + + + + + + +//#region src/output_parsers/openai_functions/json_output_functions_parsers.ts +/** +* Class for parsing the output of an LLM. Can be configured to return +* only the arguments of the function call in the output. +*/ +var OutputFunctionsParser = class extends BaseLLMOutputParser { + static lc_name() { + return "OutputFunctionsParser"; + } + lc_namespace = [ + "langchain", + "output_parsers", + "openai_functions" + ]; + lc_serializable = true; + argsOnly = true; + constructor(config) { + super(); + this.argsOnly = config?.argsOnly ?? this.argsOnly; + } + /** + * Parses the output and returns a string representation of the function + * call or its arguments. + * @param generations The output of the LLM to parse. + * @returns A string representation of the function call or its arguments. + */ + async parseResult(generations) { + if ("message" in generations[0]) { + const gen = generations[0]; + const functionCall = gen.message.additional_kwargs.function_call; + if (!functionCall) throw new Error(`No function_call in message ${JSON.stringify(generations)}`); + if (!functionCall.arguments) throw new Error(`No arguments in function_call ${JSON.stringify(generations)}`); + if (this.argsOnly) return functionCall.arguments; + return JSON.stringify(functionCall); + } else throw new Error(`No message in generations ${JSON.stringify(generations)}`); + } +}; +/** +* Class for parsing the output of an LLM into a JSON object. Uses an +* instance of `OutputFunctionsParser` to parse the output. +*/ +var JsonOutputFunctionsParser = class extends BaseCumulativeTransformOutputParser { + static lc_name() { + return "JsonOutputFunctionsParser"; + } + lc_namespace = [ + "langchain", + "output_parsers", + "openai_functions" + ]; + lc_serializable = true; + outputParser; + argsOnly = true; + constructor(config) { + super(config); + this.argsOnly = config?.argsOnly ?? this.argsOnly; + this.outputParser = new OutputFunctionsParser(config); + } + _diff(prev, next) { + if (!next) return void 0; + const ops = compare(prev ?? {}, next); + return ops; + } + async parsePartialResult(generations) { + const generation = generations[0]; + if (!generation.message) return void 0; + const { message } = generation; + const functionCall = message.additional_kwargs.function_call; + if (!functionCall) return void 0; + if (this.argsOnly) return parsePartialJson(functionCall.arguments); + return { + ...functionCall, + arguments: parsePartialJson(functionCall.arguments) + }; + } + /** + * Parses the output and returns a JSON object. If `argsOnly` is true, + * only the arguments of the function call are returned. + * @param generations The output of the LLM to parse. + * @returns A JSON object representation of the function call or its arguments. + */ + async parseResult(generations) { + const result = await this.outputParser.parseResult(generations); + if (!result) throw new Error(`No result from "OutputFunctionsParser" ${JSON.stringify(generations)}`); + return this.parse(result); + } + async parse(text) { + const parsedResult = JSON.parse(text); + if (this.argsOnly) return parsedResult; + parsedResult.arguments = JSON.parse(parsedResult.arguments); + return parsedResult; + } + getFormatInstructions() { + return ""; + } +}; +/** +* Class for parsing the output of an LLM into a JSON object and returning +* a specific attribute. Uses an instance of `JsonOutputFunctionsParser` +* to parse the output. +*/ +var JsonKeyOutputFunctionsParser = class extends BaseLLMOutputParser { + static lc_name() { + return "JsonKeyOutputFunctionsParser"; + } + lc_namespace = [ + "langchain", + "output_parsers", + "openai_functions" + ]; + lc_serializable = true; + outputParser = new JsonOutputFunctionsParser(); + attrName; + get lc_aliases() { + return { attrName: "key_name" }; + } + constructor(fields) { + super(fields); + this.attrName = fields.attrName; + } + /** + * Parses the output and returns a specific attribute of the parsed JSON + * object. + * @param generations The output of the LLM to parse. + * @returns The value of a specific attribute of the parsed JSON object. + */ + async parseResult(generations) { + const result = await this.outputParser.parseResult(generations); + return result[this.attrName]; + } +}; + +//#endregion + +//# sourceMappingURL=json_output_functions_parsers.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/openai_functions/index.js + + + +//#region src/output_parsers/openai_functions/index.ts +var openai_functions_exports = {}; +__export(openai_functions_exports, { + JsonKeyOutputFunctionsParser: () => JsonKeyOutputFunctionsParser, + JsonOutputFunctionsParser: () => JsonOutputFunctionsParser, + OutputFunctionsParser: () => OutputFunctionsParser }); -function templateLiteral(parts, params) { - return new ZodTemplateLiteral({ - type: "template_literal", - parts, - ...normalizeParams(params), - }); + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/openai_tools/json_output_tools_parsers.js + + + + + + + +//#region src/output_parsers/openai_tools/json_output_tools_parsers.ts +function parseToolCall(rawToolCall, options) { + if (rawToolCall.function === void 0) return void 0; + let functionArgs; + if (options?.partial) try { + functionArgs = parsePartialJson(rawToolCall.function.arguments ?? "{}"); + } catch { + return void 0; + } + else try { + functionArgs = JSON.parse(rawToolCall.function.arguments); + } catch (e) { + throw new OutputParserException([ + `Function "${rawToolCall.function.name}" arguments:`, + ``, + rawToolCall.function.arguments, + ``, + `are not valid JSON.`, + `Error: ${e.message}` + ].join("\n")); + } + const parsedToolCall = { + name: rawToolCall.function.name, + args: functionArgs, + type: "tool_call" + }; + if (options?.returnId) parsedToolCall.id = rawToolCall.id; + return parsedToolCall; } -const schemas_ZodLazy = /*@__PURE__*/ $constructor("ZodLazy", (inst, def) => { - $ZodLazy.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.getter(); -}); -function lazy(getter) { - return new schemas_ZodLazy({ - type: "lazy", - getter: getter, - }); +function convertLangChainToolCallToOpenAI(toolCall) { + if (toolCall.id === void 0) throw new Error(`All OpenAI tool calls must have an "id" field.`); + return { + id: toolCall.id, + type: "function", + function: { + name: toolCall.name, + arguments: JSON.stringify(toolCall.args) + } + }; } -const schemas_ZodPromise = /*@__PURE__*/ $constructor("ZodPromise", (inst, def) => { - $ZodPromise.init(inst, def); - schemas_ZodType.init(inst, def); - inst.unwrap = () => inst._zod.def.innerType; -}); -function promise(innerType) { - return new schemas_ZodPromise({ - type: "promise", - innerType: innerType, - }); +function makeInvalidToolCall(rawToolCall, errorMsg) { + return { + name: rawToolCall.function?.name, + args: rawToolCall.function?.arguments, + id: rawToolCall.id, + error: errorMsg, + type: "invalid_tool_call" + }; } -const schemas_ZodFunction = /*@__PURE__*/ $constructor("ZodFunction", (inst, def) => { - $ZodFunction.init(inst, def); - schemas_ZodType.init(inst, def); +/** +* Class for parsing the output of a tool-calling LLM into a JSON object. +*/ +var JsonOutputToolsParser = class extends BaseCumulativeTransformOutputParser { + static lc_name() { + return "JsonOutputToolsParser"; + } + returnId = false; + lc_namespace = [ + "langchain", + "output_parsers", + "openai_tools" + ]; + lc_serializable = true; + constructor(fields) { + super(fields); + this.returnId = fields?.returnId ?? this.returnId; + } + _diff() { + throw new Error("Not supported."); + } + async parse() { + throw new Error("Not implemented."); + } + async parseResult(generations) { + const result = await this.parsePartialResult(generations, false); + return result; + } + /** + * Parses the output and returns a JSON object. If `argsOnly` is true, + * only the arguments of the function call are returned. + * @param generations The output of the LLM to parse. + * @returns A JSON object representation of the function call or its arguments. + */ + async parsePartialResult(generations, partial = true) { + const message = generations[0].message; + let toolCalls; + if (isAIMessage(message) && message.tool_calls?.length) toolCalls = message.tool_calls.map((toolCall) => { + const { id,...rest } = toolCall; + if (!this.returnId) return rest; + return { + id, + ...rest + }; + }); + else if (message.additional_kwargs.tool_calls !== void 0) { + const rawToolCalls = JSON.parse(JSON.stringify(message.additional_kwargs.tool_calls)); + toolCalls = rawToolCalls.map((rawToolCall) => { + return parseToolCall(rawToolCall, { + returnId: this.returnId, + partial + }); + }); + } + if (!toolCalls) return []; + const parsedToolCalls = []; + for (const toolCall of toolCalls) if (toolCall !== void 0) { + const backwardsCompatibleToolCall = { + type: toolCall.name, + args: toolCall.args, + id: toolCall.id + }; + parsedToolCalls.push(backwardsCompatibleToolCall); + } + return parsedToolCalls; + } +}; +/** +* Class for parsing the output of a tool-calling LLM into a JSON object if you are +* expecting only a single tool to be called. +*/ +var JsonOutputKeyToolsParser = class extends JsonOutputToolsParser { + static lc_name() { + return "JsonOutputKeyToolsParser"; + } + lc_namespace = [ + "langchain", + "output_parsers", + "openai_tools" + ]; + lc_serializable = true; + returnId = false; + /** The type of tool calls to return. */ + keyName; + /** Whether to return only the first tool call. */ + returnSingle = false; + zodSchema; + constructor(params) { + super(params); + this.keyName = params.keyName; + this.returnSingle = params.returnSingle ?? this.returnSingle; + this.zodSchema = params.zodSchema; + } + async _validateResult(result) { + if (this.zodSchema === void 0) return result; + const zodParsedResult = await interopSafeParseAsync(this.zodSchema, result); + if (zodParsedResult.success) return zodParsedResult.data; + else throw new OutputParserException(`Failed to parse. Text: "${JSON.stringify(result, null, 2)}". Error: ${JSON.stringify(zodParsedResult.error?.issues)}`, JSON.stringify(result, null, 2)); + } + async parsePartialResult(generations) { + const results = await super.parsePartialResult(generations); + const matchingResults = results.filter((result) => result.type === this.keyName); + let returnedValues = matchingResults; + if (!matchingResults.length) return void 0; + if (!this.returnId) returnedValues = matchingResults.map((result) => result.args); + if (this.returnSingle) return returnedValues[0]; + return returnedValues; + } + async parseResult(generations) { + const results = await super.parsePartialResult(generations, false); + const matchingResults = results.filter((result) => result.type === this.keyName); + let returnedValues = matchingResults; + if (!matchingResults.length) return void 0; + if (!this.returnId) returnedValues = matchingResults.map((result) => result.args); + if (this.returnSingle) return this._validateResult(returnedValues[0]); + const toolCallResults = await Promise.all(returnedValues.map((value) => this._validateResult(value))); + return toolCallResults; + } +}; + +//#endregion + +//# sourceMappingURL=json_output_tools_parsers.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/openai_tools/index.js + + + +//#region src/output_parsers/openai_tools/index.ts +var openai_tools_exports = {}; +__export(openai_tools_exports, { + JsonOutputKeyToolsParser: () => JsonOutputKeyToolsParser, + JsonOutputToolsParser: () => JsonOutputToolsParser, + convertLangChainToolCallToOpenAI: () => convertLangChainToolCallToOpenAI, + makeInvalidToolCall: () => makeInvalidToolCall, + parseToolCall: () => parseToolCall }); -function _function(params) { - return new schemas_ZodFunction({ - type: "function", - input: Array.isArray(params?.input) ? tuple(params?.input) : (params?.input ?? array(unknown())), - output: params?.output ?? unknown(), - }); -} -const ZodCustom = /*@__PURE__*/ $constructor("ZodCustom", (inst, def) => { - $ZodCustom.init(inst, def); - schemas_ZodType.init(inst, def); -}); -// custom checks -function check(fn) { - const ch = new $ZodCheck({ - check: "custom", - // ...util.normalizeParams(params), - }); - ch._zod.check = fn; - return ch; -} -function schemas_custom(fn, _params) { - return _custom(ZodCustom, fn ?? (() => true), _params); +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/base.js + + +//#region src/prompts/base.ts +/** +* Base class for prompt templates. Exposes a format method that returns a +* string prompt given a set of input values. +*/ +var BasePromptTemplate = class extends Runnable { + lc_serializable = true; + lc_namespace = [ + "langchain_core", + "prompts", + this._getPromptType() + ]; + get lc_attributes() { + return { partialVariables: void 0 }; + } + inputVariables; + outputParser; + partialVariables; + /** + * Metadata to be used for tracing. + */ + metadata; + /** Tags to be used for tracing. */ + tags; + constructor(input) { + super(input); + const { inputVariables } = input; + if (inputVariables.includes("stop")) throw new Error("Cannot have an input variable named 'stop', as it is used internally, please rename."); + Object.assign(this, input); + } + /** + * Merges partial variables and user variables. + * @param userVariables The user variables to merge with the partial variables. + * @returns A Promise that resolves to an object containing the merged variables. + */ + async mergePartialAndUserVariables(userVariables) { + const partialVariables = this.partialVariables ?? {}; + const partialValues = {}; + for (const [key, value] of Object.entries(partialVariables)) if (typeof value === "string") partialValues[key] = value; + else partialValues[key] = await value(); + const allKwargs = { + ...partialValues, + ...userVariables + }; + return allKwargs; + } + /** + * Invokes the prompt template with the given input and options. + * @param input The input to invoke the prompt template with. + * @param options Optional configuration for the callback. + * @returns A Promise that resolves to the output of the prompt template. + */ + async invoke(input, options) { + const metadata = { + ...this.metadata, + ...options?.metadata + }; + const tags = [...this.tags ?? [], ...options?.tags ?? []]; + return this._callWithConfig((input$1) => this.formatPromptValue(input$1), input, { + ...options, + tags, + metadata, + runType: "prompt" + }); + } +}; + +//#endregion + +//# sourceMappingURL=base.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/string.js + + + +//#region src/prompts/string.ts +/** +* Base class for string prompt templates. It extends the +* BasePromptTemplate class and overrides the formatPromptValue method to +* return a StringPromptValue. +*/ +var BaseStringPromptTemplate = class extends BasePromptTemplate { + /** + * Formats the prompt given the input values and returns a formatted + * prompt value. + * @param values The input values to format the prompt. + * @returns A Promise that resolves to a formatted prompt value. + */ + async formatPromptValue(values) { + const formattedPrompt = await this.format(values); + return new StringPromptValue(formattedPrompt); + } +}; + +//#endregion + +//# sourceMappingURL=string.js.map +;// CONCATENATED MODULE: ./node_modules/mustache/mustache.mjs +/*! + * mustache.js - Logic-less {{mustache}} templates with JavaScript + * http://github.com/janl/mustache.js + */ + +var mustache_objectToString = Object.prototype.toString; +var mustache_isArray = Array.isArray || function isArrayPolyfill (object) { + return mustache_objectToString.call(object) === '[object Array]'; +}; + +function isFunction (object) { + return typeof object === 'function'; } -function refine(fn, _params = {}) { - return _refine(ZodCustom, fn, _params); + +/** + * More correct typeof string handling array + * which normally returns typeof 'object' + */ +function typeStr (obj) { + return mustache_isArray(obj) ? 'array' : typeof obj; } -// superRefine -function superRefine(fn) { - return _superRefine(fn); + +function escapeRegExp (string) { + return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); } -// Re-export describe and meta from core -const schemas_describe = describe; -const schemas_meta = meta; -function _instanceof(cls, params = { - error: `Input not instance of ${cls.name}`, -}) { - const inst = new ZodCustom({ - type: "custom", - check: "custom", - fn: (data) => data instanceof cls, - abort: true, - ...normalizeParams(params), - }); - inst._zod.bag.Class = cls; - return inst; + +/** + * Null safe way of checking whether or not an object, + * including its prototype, has a given property + */ +function hasProperty (obj, propName) { + return obj != null && typeof obj === 'object' && (propName in obj); } -// stringbool -const stringbool = (...args) => _stringbool({ - Codec: ZodCodec, - Boolean: schemas_ZodBoolean, - String: schemas_ZodString, -}, ...args); -function json(params) { - const jsonSchema = lazy(() => { - return union([schemas_string(params), schemas_number(), schemas_boolean(), schemas_null(), array(jsonSchema), record(schemas_string(), jsonSchema)]); - }); - return jsonSchema; +/** + * Safe way of detecting whether or not the given thing is a primitive and + * whether it has the given property + */ +function primitiveHasOwnProperty (primitive, propName) { + return ( + primitive != null + && typeof primitive !== 'object' + && primitive.hasOwnProperty + && primitive.hasOwnProperty(propName) + ); } -// preprocess -// /** @deprecated Use `z.pipe()` and `z.transform()` instead. */ -function preprocess(fn, schema) { - return pipe(transform(fn), schema); + +// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 +// See https://github.com/janl/mustache.js/issues/189 +var regExpTest = RegExp.prototype.test; +function testRegExp (re, string) { + return regExpTest.call(re, string); } -;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/compat.js -// Zod 3 compat layer - -/** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */ -const compat_ZodIssueCode = { - invalid_type: "invalid_type", - too_big: "too_big", - too_small: "too_small", - invalid_format: "invalid_format", - not_multiple_of: "not_multiple_of", - unrecognized_keys: "unrecognized_keys", - invalid_union: "invalid_union", - invalid_key: "invalid_key", - invalid_element: "invalid_element", - invalid_value: "invalid_value", - custom: "custom", -}; - -/** @deprecated Use `z.config(params)` instead. */ -function compat_setErrorMap(map) { - config({ - customError: map, - }); +var nonSpaceRe = /\S/; +function isWhitespace (string) { + return !testRegExp(nonSpaceRe, string); } -/** @deprecated Use `z.config()` instead. */ -function compat_getErrorMap() { - return config().customError; + +var entityMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/', + '`': '`', + '=': '=' +}; + +function escapeHtml (string) { + return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) { + return entityMap[s]; + }); } -/** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */ -var compat_ZodFirstPartyTypeKind; -(function (ZodFirstPartyTypeKind) { -})(compat_ZodFirstPartyTypeKind || (compat_ZodFirstPartyTypeKind = {})); -;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/coerce.js +var whiteRe = /\s*/; +var spaceRe = /\s+/; +var equalsRe = /\s*=/; +var curlyRe = /\s*\}/; +var tagRe = /#|\^|\/|>|\{|&|=|!/; + +/** + * Breaks up the given `template` string into a tree of tokens. If the `tags` + * argument is given here it must be an array with two string values: the + * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of + * course, the default is to use mustaches (i.e. mustache.tags). + * + * A token is an array with at least 4 elements. The first element is the + * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag + * did not contain a symbol (i.e. {{myValue}}) this element is "name". For + * all text that appears outside a symbol this element is "text". + * + * The second element of a token is its "value". For mustache tags this is + * whatever else was inside the tag besides the opening symbol. For text tokens + * this is the text itself. + * + * The third and fourth elements of the token are the start and end indices, + * respectively, of the token in the original template. + * + * Tokens that are the root node of a subtree contain two more elements: 1) an + * array of tokens in the subtree and 2) the index in the original template at + * which the closing tag for that section begins. + * + * Tokens for partials also contain two more elements: 1) a string value of + * indendation prior to that tag and 2) the index of that tag on that line - + * eg a value of 2 indicates the partial is the third tag on this line. + */ +function parseTemplate (template, tags) { + if (!template) + return []; + var lineHasNonSpace = false; + var sections = []; // Stack to hold section tokens + var tokens = []; // Buffer to hold the tokens + var spaces = []; // Indices of whitespace tokens on the current line + var hasTag = false; // Is there a {{tag}} on the current line? + var nonSpace = false; // Is there a non-space char on the current line? + var indentation = ''; // Tracks indentation for tags that use it + var tagIndex = 0; // Stores a count of number of tags encountered on a line + + // Strips all whitespace tokens array for the current line + // if there was a {{#tag}} on it and otherwise only space. + function stripSpace () { + if (hasTag && !nonSpace) { + while (spaces.length) + delete tokens[spaces.pop()]; + } else { + spaces = []; + } + hasTag = false; + nonSpace = false; + } -function coerce_string(params) { - return _coercedString(schemas_ZodString, params); -} -function coerce_number(params) { - return _coercedNumber(schemas_ZodNumber, params); + var openingTagRe, closingTagRe, closingCurlyRe; + function compileTags (tagsToCompile) { + if (typeof tagsToCompile === 'string') + tagsToCompile = tagsToCompile.split(spaceRe, 2); + + if (!mustache_isArray(tagsToCompile) || tagsToCompile.length !== 2) + throw new Error('Invalid tags: ' + tagsToCompile); + + openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*'); + closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1])); + closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1])); + } + + compileTags(tags || mustache.tags); + + var scanner = new Scanner(template); + + var start, type, value, chr, token, openSection; + while (!scanner.eos()) { + start = scanner.pos; + + // Match any text between tags. + value = scanner.scanUntil(openingTagRe); + + if (value) { + for (var i = 0, valueLength = value.length; i < valueLength; ++i) { + chr = value.charAt(i); + + if (isWhitespace(chr)) { + spaces.push(tokens.length); + indentation += chr; + } else { + nonSpace = true; + lineHasNonSpace = true; + indentation += ' '; + } + + tokens.push([ 'text', chr, start, start + 1 ]); + start += 1; + + // Check for whitespace on the current line. + if (chr === '\n') { + stripSpace(); + indentation = ''; + tagIndex = 0; + lineHasNonSpace = false; + } + } + } + + // Match the opening tag. + if (!scanner.scan(openingTagRe)) + break; + + hasTag = true; + + // Get the tag type. + type = scanner.scan(tagRe) || 'name'; + scanner.scan(whiteRe); + + // Get the tag value. + if (type === '=') { + value = scanner.scanUntil(equalsRe); + scanner.scan(equalsRe); + scanner.scanUntil(closingTagRe); + } else if (type === '{') { + value = scanner.scanUntil(closingCurlyRe); + scanner.scan(curlyRe); + scanner.scanUntil(closingTagRe); + type = '&'; + } else { + value = scanner.scanUntil(closingTagRe); + } + + // Match the closing tag. + if (!scanner.scan(closingTagRe)) + throw new Error('Unclosed tag at ' + scanner.pos); + + if (type == '>') { + token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ]; + } else { + token = [ type, value, start, scanner.pos ]; + } + tagIndex++; + tokens.push(token); + + if (type === '#' || type === '^') { + sections.push(token); + } else if (type === '/') { + // Check section nesting. + openSection = sections.pop(); + + if (!openSection) + throw new Error('Unopened section "' + value + '" at ' + start); + + if (openSection[1] !== value) + throw new Error('Unclosed section "' + openSection[1] + '" at ' + start); + } else if (type === 'name' || type === '{' || type === '&') { + nonSpace = true; + } else if (type === '=') { + // Set the tags for the next time around. + compileTags(value); + } + } + + stripSpace(); + + // Make sure there are no open sections when we're done. + openSection = sections.pop(); + + if (openSection) + throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos); + + return nestTokens(squashTokens(tokens)); } -function coerce_boolean(params) { - return _coercedBoolean(schemas_ZodBoolean, params); + +/** + * Combines the values of consecutive text tokens in the given `tokens` array + * to a single token. + */ +function squashTokens (tokens) { + var squashedTokens = []; + + var token, lastToken; + for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { + token = tokens[i]; + + if (token) { + if (token[0] === 'text' && lastToken && lastToken[0] === 'text') { + lastToken[1] += token[1]; + lastToken[3] = token[3]; + } else { + squashedTokens.push(token); + lastToken = token; + } + } + } + + return squashedTokens; } -function coerce_bigint(params) { - return _coercedBigint(schemas_ZodBigInt, params); + +/** + * Forms the given array of `tokens` into a nested tree structure where + * tokens that represent a section have two additional items: 1) an array of + * all tokens that appear in that section and 2) the index in the original + * template that represents the end of that section. + */ +function nestTokens (tokens) { + var nestedTokens = []; + var collector = nestedTokens; + var sections = []; + + var token, section; + for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { + token = tokens[i]; + + switch (token[0]) { + case '#': + case '^': + collector.push(token); + sections.push(token); + collector = token[4] = []; + break; + case '/': + section = sections.pop(); + section[5] = token[2]; + collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens; + break; + default: + collector.push(token); + } + } + + return nestedTokens; } -function coerce_date(params) { - return _coercedDate(schemas_ZodDate, params); + +/** + * A simple string scanner that is used by the template parser to find + * tokens in template strings. + */ +function Scanner (string) { + this.string = string; + this.tail = string; + this.pos = 0; } -;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/external.js +/** + * Returns `true` if the tail is empty (end of string). + */ +Scanner.prototype.eos = function eos () { + return this.tail === ''; +}; + +/** + * Tries to match the given regular expression at the current position. + * Returns the matched text if it can match, the empty string otherwise. + */ +Scanner.prototype.scan = function scan (re) { + var match = this.tail.match(re); + + if (!match || match.index !== 0) + return ''; + + var string = match[0]; + + this.tail = this.tail.substring(string.length); + this.pos += string.length; + + return string; +}; + +/** + * Skips all text until the given regular expression can be matched. Returns + * the skipped string, which is the entire tail if no match can be made. + */ +Scanner.prototype.scanUntil = function scanUntil (re) { + var index = this.tail.search(re), match; + switch (index) { + case -1: + match = this.tail; + this.tail = ''; + break; + case 0: + match = ''; + break; + default: + match = this.tail.substring(0, index); + this.tail = this.tail.substring(index); + } + this.pos += match.length; + return match; +}; +/** + * Represents a rendering context by wrapping a view object and + * maintaining a reference to the parent context. + */ +function Context (view, parentContext) { + this.view = view; + this.cache = { '.': this.view }; + this.parent = parentContext; +} +/** + * Creates a new context using the given view with this context + * as the parent. + */ +Context.prototype.push = function push (view) { + return new Context(view, this); +}; -// zod-specified +/** + * Returns the value of the given name in this context, traversing + * up the context hierarchy if the value is absent in this context's view. + */ +Context.prototype.lookup = function lookup (name) { + var cache = this.cache; + var value; + if (cache.hasOwnProperty(name)) { + value = cache[name]; + } else { + var context = this, intermediateValue, names, index, lookupHit = false; -config(en()); + while (context) { + if (name.indexOf('.') > 0) { + intermediateValue = context.view; + names = name.split('.'); + index = 0; + /** + * Using the dot notion path in `name`, we descend through the + * nested objects. + * + * To be certain that the lookup has been successful, we have to + * check if the last object in the path actually has the property + * we are looking for. We store the result in `lookupHit`. + * + * This is specially necessary for when the value has been set to + * `undefined` and we want to avoid looking up parent contexts. + * + * In the case where dot notation is used, we consider the lookup + * to be successful even if the last "object" in the path is + * not actually an object but a primitive (e.g., a string, or an + * integer), because it is sometimes useful to access a property + * of an autoboxed primitive, such as the length of a string. + **/ + while (intermediateValue != null && index < names.length) { + if (index === names.length - 1) + lookupHit = ( + hasProperty(intermediateValue, names[index]) + || primitiveHasOwnProperty(intermediateValue, names[index]) + ); -// iso -// must be exported from top-level -// https://github.com/colinhacks/zod/issues/4491 + intermediateValue = intermediateValue[names[index++]]; + } + } else { + intermediateValue = context.view[name]; + /** + * Only checking against `hasProperty`, which always returns `false` if + * `context.view` is not an object. Deliberately omitting the check + * against `primitiveHasOwnProperty` if dot notation is not used. + * + * Consider this example: + * ``` + * Mustache.render("The length of a football field is {{#length}}{{length}}{{/length}}.", {length: "100 yards"}) + * ``` + * + * If we were to check also against `primitiveHasOwnProperty`, as we do + * in the dot notation case, then render call would return: + * + * "The length of a football field is 9." + * + * rather than the expected: + * + * "The length of a football field is 100 yards." + **/ + lookupHit = hasProperty(context.view, name); + } + if (lookupHit) { + value = intermediateValue; + break; + } + context = context.parent; + } -;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/index.js + cache[name] = value; + } + if (isFunction(value)) + value = value.call(this.view); + return value; +}; -/* harmony default export */ const classic = ((/* unused pure expression or super */ null && (z))); +/** + * A Writer knows how to take a stream of tokens and render them to a + * string, given a context. It also maintains a cache of templates to + * avoid the need to parse the same template twice. + */ +function Writer () { + this.templateCache = { + _cache: {}, + set: function set (key, value) { + this._cache[key] = value; + }, + get: function get (key) { + return this._cache[key]; + }, + clear: function clear () { + this._cache = {}; + } + }; +} -;// CONCATENATED MODULE: ./node_modules/zod/v4/index.js +/** + * Clears all cached templates in this writer. + */ +Writer.prototype.clearCache = function clearCache () { + if (typeof this.templateCache !== 'undefined') { + this.templateCache.clear(); + } +}; +/** + * Parses and caches the given `template` according to the given `tags` or + * `mustache.tags` if `tags` is omitted, and returns the array of tokens + * that is generated from the parse. + */ +Writer.prototype.parse = function parse (template, tags) { + var cache = this.templateCache; + var cacheKey = template + ':' + (tags || mustache.tags).join(':'); + var isCacheEnabled = typeof cache !== 'undefined'; + var tokens = isCacheEnabled ? cache.get(cacheKey) : undefined; -/* harmony default export */ const zod_v4 = ((/* unused pure expression or super */ null && (z4))); + if (tokens == undefined) { + tokens = parseTemplate(template, tags); + isCacheEnabled && cache.set(cacheKey, tokens); + } + return tokens; +}; -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tools/index.js +/** + * High-level method that is used to render the given `template` with + * the given `view`. + * + * The optional `partials` argument may be an object that contains the + * names and templates of partials that are used in the template. It may + * also be a function that is used to load partial templates on the fly + * that takes a single argument: the name of the partial. + * + * If the optional `config` argument is given here, then it should be an + * object with a `tags` attribute or an `escape` attribute or both. + * If an array is passed, then it will be interpreted the same way as + * a `tags` attribute on a `config` object. + * + * The `tags` attribute of a `config` object must be an array with two + * string values: the opening and closing tags used in the template (e.g. + * [ "<%", "%>" ]). The default is to mustache.tags. + * + * The `escape` attribute of a `config` object must be a function which + * accepts a string as input and outputs a safely escaped string. + * If an `escape` function is not provided, then an HTML-safe string + * escaping function is used as the default. + */ +Writer.prototype.render = function render (template, view, partials, config) { + var tags = this.getConfigTags(config); + var tokens = this.parse(template, tags); + var context = (view instanceof Context) ? view : new Context(view, undefined); + return this.renderTokens(tokens, context, partials, template, config); +}; +/** + * Low-level method that renders the given array of `tokens` using + * the given `context` and `partials`. + * + * Note: The `originalTemplate` is only ever used to extract the portion + * of the original template that was contained in a higher-order section. + * If the template doesn't use higher-order sections, this argument may + * be omitted. + */ +Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate, config) { + var buffer = ''; + var token, symbol, value; + for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { + value = undefined; + token = tokens[i]; + symbol = token[0]; + if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate, config); + else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate, config); + else if (symbol === '>') value = this.renderPartial(token, context, partials, config); + else if (symbol === '&') value = this.unescapedValue(token, context); + else if (symbol === 'name') value = this.escapedValue(token, context, config); + else if (symbol === 'text') value = this.rawValue(token); + if (value !== undefined) + buffer += value; + } + return buffer; +}; +Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate, config) { + var self = this; + var buffer = ''; + var value = context.lookup(token[1]); + // This function is used to render an arbitrary template + // in the current context by higher-order sections. + function subRender (template) { + return self.render(template, context, partials, config); + } + if (!value) return; + if (mustache_isArray(value)) { + for (var j = 0, valueLength = value.length; j < valueLength; ++j) { + buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate, config); + } + } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') { + buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate, config); + } else if (isFunction(value)) { + if (typeof originalTemplate !== 'string') + throw new Error('Cannot use higher-order sections without the original template'); + // Extract the portion of the original template that the section contains. + value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender); + if (value != null) + buffer += value; + } else { + buffer += this.renderTokens(token[4], context, partials, originalTemplate, config); + } + return buffer; +}; +Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate, config) { + var value = context.lookup(token[1]); + // Use JavaScript's definition of falsy. Include empty arrays. + // See https://github.com/janl/mustache.js/issues/186 + if (!value || (mustache_isArray(value) && value.length === 0)) + return this.renderTokens(token[4], context, partials, originalTemplate, config); +}; +Writer.prototype.indentPartial = function indentPartial (partial, indentation, lineHasNonSpace) { + var filteredIndentation = indentation.replace(/[^ \t]/g, ''); + var partialByNl = partial.split('\n'); + for (var i = 0; i < partialByNl.length; i++) { + if (partialByNl[i].length && (i > 0 || !lineHasNonSpace)) { + partialByNl[i] = filteredIndentation + partialByNl[i]; + } + } + return partialByNl.join('\n'); +}; +Writer.prototype.renderPartial = function renderPartial (token, context, partials, config) { + if (!partials) return; + var tags = this.getConfigTags(config); -//#region src/tools/index.ts -var tools_exports = {}; -__export(tools_exports, { - BaseToolkit: () => BaseToolkit, - DynamicStructuredTool: () => tools_DynamicStructuredTool, - DynamicTool: () => tools_DynamicTool, - StructuredTool: () => StructuredTool, - Tool: () => Tool, - ToolInputParsingException: () => ToolInputParsingException, - isLangChainTool: () => isLangChainTool, - isRunnableToolLike: () => isRunnableToolLike, - isStructuredTool: () => isStructuredTool, - isStructuredToolParams: () => isStructuredToolParams, - tool: () => tool -}); -/** -* Base class for Tools that accept input of any shape defined by a Zod schema. -*/ -var StructuredTool = class extends BaseLangChain { - /** - * Whether to return the tool's output directly. - * - * Setting this to true means that after the tool is called, - * an agent should stop looping. - */ - returnDirect = false; - verboseParsingErrors = false; - get lc_namespace() { - return ["langchain", "tools"]; - } - /** - * The tool response format. - * - * If "content" then the output of the tool is interpreted as the contents of a - * ToolMessage. If "content_and_artifact" then the output is expected to be a - * two-tuple corresponding to the (content, artifact) of a ToolMessage. - * - * @default "content" - */ - responseFormat = "content"; - /** - * Default config object for the tool runnable. - */ - defaultConfig; - constructor(fields) { - super(fields ?? {}); - this.verboseParsingErrors = fields?.verboseParsingErrors ?? this.verboseParsingErrors; - this.responseFormat = fields?.responseFormat ?? this.responseFormat; - this.defaultConfig = fields?.defaultConfig ?? this.defaultConfig; - this.metadata = fields?.metadata ?? this.metadata; - } - /** - * Invokes the tool with the provided input and configuration. - * @param input The input for the tool. - * @param config Optional configuration for the tool. - * @returns A Promise that resolves with the tool's output. - */ - async invoke(input, config) { - let toolInput; - let enrichedConfig = ensureConfig(mergeConfigs(this.defaultConfig, config)); - if (_isToolCall(input)) { - toolInput = input.args; - enrichedConfig = { - ...enrichedConfig, - toolCall: input - }; - } else toolInput = input; - return this.call(toolInput, enrichedConfig); - } - /** - * @deprecated Use .invoke() instead. Will be removed in 0.3.0. - * - * Calls the tool with the provided argument, configuration, and tags. It - * parses the input according to the schema, handles any errors, and - * manages callbacks. - * @param arg The input argument for the tool. - * @param configArg Optional configuration or callbacks for the tool. - * @param tags Optional tags for the tool. - * @returns A Promise that resolves with a string. - */ - async call(arg, configArg, tags) { - const inputForValidation = _isToolCall(arg) ? arg.args : arg; - let parsed; - if (isInteropZodSchema(this.schema)) try { - parsed = await interopParseAsync(this.schema, inputForValidation); - } catch (e) { - let message = `Received tool input did not match expected schema`; - if (this.verboseParsingErrors) message = `${message}\nDetails: ${e.message}`; - if (isInteropZodError(e)) message = `${message}\n\n${prettifyError(e)}`; - throw new ToolInputParsingException(message, JSON.stringify(arg)); - } - else { - const result$1 = validate_validate(inputForValidation, this.schema); - if (!result$1.valid) { - let message = `Received tool input did not match expected schema`; - if (this.verboseParsingErrors) message = `${message}\nDetails: ${result$1.errors.map((e) => `${e.keywordLocation}: ${e.error}`).join("\n")}`; - throw new ToolInputParsingException(message, JSON.stringify(arg)); - } - parsed = inputForValidation; - } - const config = parseCallbackConfigArg(configArg); - const callbackManager_ = CallbackManager.configure(config.callbacks, this.callbacks, config.tags || tags, this.tags, config.metadata, this.metadata, { verbose: this.verbose }); - const runManager = await callbackManager_?.handleToolStart(this.toJSON(), typeof arg === "string" ? arg : JSON.stringify(arg), config.runId, void 0, void 0, void 0, config.runName); - delete config.runId; - let result; - try { - result = await this._call(parsed, runManager, config); - } catch (e) { - await runManager?.handleToolError(e); - throw e; - } - let content; - let artifact; - if (this.responseFormat === "content_and_artifact") if (Array.isArray(result) && result.length === 2) [content, artifact] = result; - else throw new Error(`Tool response format is "content_and_artifact" but the output was not a two-tuple.\nResult: ${JSON.stringify(result)}`); - else content = result; - let toolCallId; - if (_isToolCall(arg)) toolCallId = arg.id; - if (!toolCallId && _configHasToolCallId(config)) toolCallId = config.toolCall.id; - const formattedOutput = _formatToolOutput({ - content, - artifact, - toolCallId, - name: this.name, - metadata: this.metadata - }); - await runManager?.handleToolEnd(formattedOutput); - return formattedOutput; - } + var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; + if (value != null) { + var lineHasNonSpace = token[6]; + var tagIndex = token[5]; + var indentation = token[4]; + var indentedValue = value; + if (tagIndex == 0 && indentation) { + indentedValue = this.indentPartial(value, indentation, lineHasNonSpace); + } + var tokens = this.parse(indentedValue, tags); + return this.renderTokens(tokens, context, partials, indentedValue, config); + } }; -/** -* Base class for Tools that accept input as a string. -*/ -var Tool = class extends StructuredTool { - schema = objectType({ input: stringType().optional() }).transform((obj) => obj.input); - constructor(fields) { - super(fields); - } - /** - * @deprecated Use .invoke() instead. Will be removed in 0.3.0. - * - * Calls the tool with the provided argument and callbacks. It handles - * string inputs specifically. - * @param arg The input argument for the tool, which can be a string, undefined, or an input of the tool's schema. - * @param callbacks Optional callbacks for the tool. - * @returns A Promise that resolves with a string. - */ - call(arg, callbacks) { - const structuredArg = typeof arg === "string" || arg == null ? { input: arg } : arg; - return super.call(structuredArg, callbacks); - } + +Writer.prototype.unescapedValue = function unescapedValue (token, context) { + var value = context.lookup(token[1]); + if (value != null) + return value; }; -/** -* A tool that can be created dynamically from a function, name, and description. -*/ -var tools_DynamicTool = class extends Tool { - static lc_name() { - return "DynamicTool"; - } - name; - description; - func; - constructor(fields) { - super(fields); - this.name = fields.name; - this.description = fields.description; - this.func = fields.func; - this.returnDirect = fields.returnDirect ?? this.returnDirect; - } - /** - * @deprecated Use .invoke() instead. Will be removed in 0.3.0. - */ - async call(arg, configArg) { - const config = parseCallbackConfigArg(configArg); - if (config.runName === void 0) config.runName = this.name; - return super.call(arg, config); - } - /** @ignore */ - async _call(input, runManager, parentConfig) { - return this.func(input, runManager, parentConfig); - } + +Writer.prototype.escapedValue = function escapedValue (token, context, config) { + var escape = this.getConfigEscape(config) || mustache.escape; + var value = context.lookup(token[1]); + if (value != null) + return (typeof value === 'number' && escape === mustache.escape) ? String(value) : escape(value); }; -/** -* A tool that can be created dynamically from a function, name, and -* description, designed to work with structured data. It extends the -* StructuredTool class and overrides the _call method to execute the -* provided function when the tool is called. -* -* Schema can be passed as Zod or JSON schema. The tool will not validate -* input if JSON schema is passed. -*/ -var tools_DynamicStructuredTool = class extends StructuredTool { - static lc_name() { - return "DynamicStructuredTool"; - } - name; - description; - func; - schema; - constructor(fields) { - super(fields); - this.name = fields.name; - this.description = fields.description; - this.func = fields.func; - this.returnDirect = fields.returnDirect ?? this.returnDirect; - this.schema = fields.schema; - } - /** - * @deprecated Use .invoke() instead. Will be removed in 0.3.0. - */ - async call(arg, configArg, tags) { - const config = parseCallbackConfigArg(configArg); - if (config.runName === void 0) config.runName = this.name; - return super.call(arg, config, tags); - } - _call(arg, runManager, parentConfig) { - return this.func(arg, runManager, parentConfig); - } + +Writer.prototype.rawValue = function rawValue (token) { + return token[1]; }; -/** -* Abstract base class for toolkits in LangChain. Toolkits are collections -* of tools that agents can use. Subclasses must implement the `tools` -* property to provide the specific tools for the toolkit. -*/ -var BaseToolkit = class { - getTools() { - return this.tools; - } + +Writer.prototype.getConfigTags = function getConfigTags (config) { + if (mustache_isArray(config)) { + return config; + } + else if (config && typeof config === 'object') { + return config.tags; + } + else { + return undefined; + } +}; + +Writer.prototype.getConfigEscape = function getConfigEscape (config) { + if (config && typeof config === 'object' && !mustache_isArray(config)) { + return config.escape; + } + else { + return undefined; + } }; -function tool(func, fields) { - const isSimpleStringSchema = isSimpleStringZodSchema(fields.schema); - const isStringJSONSchema = validatesOnlyStrings(fields.schema); - if (!fields.schema || isSimpleStringSchema || isStringJSONSchema) return new tools_DynamicTool({ - ...fields, - description: fields.description ?? fields.schema?.description ?? `${fields.name} tool`, - func: async (input, runManager, config) => { - return new Promise((resolve, reject) => { - const childConfig = config_patchConfig(config, { callbacks: runManager?.getChild() }); - async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(childConfig), async () => { - try { - resolve(func(input, childConfig)); - } catch (e) { - reject(e); - } - }); - }); - } - }); - const schema = fields.schema; - const description = fields.description ?? fields.schema.description ?? `${fields.name} tool`; - return new tools_DynamicStructuredTool({ - ...fields, - description, - schema, - func: async (input, runManager, config) => { - return new Promise((resolve, reject) => { - let listener; - const cleanup = () => { - if (config?.signal && listener) config.signal.removeEventListener("abort", listener); - }; - if (config?.signal) { - listener = () => { - cleanup(); - reject(getAbortSignalError(config.signal)); - }; - config.signal.addEventListener("abort", listener); - } - const childConfig = config_patchConfig(config, { callbacks: runManager?.getChild() }); - async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(childConfig), async () => { - try { - const result = await func(input, childConfig); - /** - * If the signal is aborted, we don't want to resolve the promise - * as the promise is already rejected. - */ - if (config?.signal?.aborted) { - cleanup(); - return; - } - cleanup(); - resolve(result); - } catch (e) { - cleanup(); - reject(e); - } - }); - }); - } - }); -} -function _formatToolOutput(params) { - const { content, artifact, toolCallId, metadata } = params; - if (toolCallId && !isDirectToolOutput(content)) if (typeof content === "string" || Array.isArray(content) && content.every((item) => typeof item === "object")) return new ToolMessage({ - status: "success", - content, - artifact, - tool_call_id: toolCallId, - name: params.name, - metadata - }); - else return new ToolMessage({ - status: "success", - content: tools_stringify(content), - artifact, - tool_call_id: toolCallId, - name: params.name, - metadata - }); - else return content; -} -function tools_stringify(content) { - try { - return JSON.stringify(content, null, 2) ?? ""; - } catch (_noOp) { - return `${content}`; - } -} -//#endregion +var mustache = { + name: 'mustache.js', + version: '4.2.0', + tags: [ '{{', '}}' ], + clearCache: undefined, + escape: undefined, + parse: undefined, + render: undefined, + Scanner: undefined, + Context: undefined, + Writer: undefined, + /** + * Allows a user to override the default caching strategy, by providing an + * object with set, get and clear methods. This can also be used to disable + * the cache by setting it to the literal `undefined`. + */ + set templateCache (cache) { + defaultWriter.templateCache = cache; + }, + /** + * Gets the default or overridden caching object from the default writer. + */ + get templateCache () { + return defaultWriter.templateCache; + } +}; -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/chat_models.js +// All high-level mustache.* functions use this writer. +var defaultWriter = new Writer(); +/** + * Clears all cached templates in the default writer. + */ +mustache.clearCache = function clearCache () { + return defaultWriter.clearCache(); +}; +/** + * Parses and caches the given template in the default writer and returns the + * array of tokens it contains. Doing this ahead of time avoids the need to + * parse templates on the fly as they are rendered. + */ +mustache.parse = function parse (template, tags) { + return defaultWriter.parse(template, tags); +}; +/** + * Renders the `template` with the given `view`, `partials`, and `config` + * using the default writer. + */ +mustache.render = function render (template, view, partials, config) { + if (typeof template !== 'string') { + throw new TypeError('Invalid template! Template should be a "string" ' + + 'but "' + typeStr(template) + '" was given as the first ' + + 'argument for mustache#render(template, view, partials)'); + } + return defaultWriter.render(template, view, partials, config); +}; +// Export the escaping function so that the user may override it. +// See https://github.com/janl/mustache.js/issues/244 +mustache.escape = escapeHtml; +// Export these mainly for testing, but also for advanced usage. +mustache.Scanner = Scanner; +mustache.Context = Context; +mustache.Writer = Writer; -//#region src/utils/testing/chat_models.ts -var FakeChatModel = class extends BaseChatModel { - _combineLLMOutput() { - return []; - } - _llmType() { - return "fake"; - } - async _generate(messages, options, runManager) { - if (options?.stop?.length) return { generations: [{ - message: new AIMessage(options.stop[0]), - text: options.stop[0] - }] }; - const text = messages.map((m) => { - if (typeof m.content === "string") return m.content; - return JSON.stringify(m.content, null, 2); - }).join("\n"); - await runManager?.handleLLMNewToken(text); - return { - generations: [{ - message: new AIMessage(text), - text - }], - llmOutput: {} - }; - } -}; -var FakeStreamingChatModel = class FakeStreamingChatModel extends BaseChatModel { - sleep = 50; - responses = []; - chunks = []; - toolStyle = "openai"; - thrownErrorString; - tools = []; - constructor({ sleep = 50, responses = [], chunks = [], toolStyle = "openai", thrownErrorString,...rest }) { - super(rest); - this.sleep = sleep; - this.responses = responses; - this.chunks = chunks; - this.toolStyle = toolStyle; - this.thrownErrorString = thrownErrorString; - } - _llmType() { - return "fake"; - } - bindTools(tools) { - const merged = [...this.tools, ...tools]; - const toolDicts = merged.map((t) => { - switch (this.toolStyle) { - case "openai": return { - type: "function", - function: { - name: t.name, - description: t.description, - parameters: toJsonSchema(t.schema) - } - }; - case "anthropic": return { - name: t.name, - description: t.description, - input_schema: toJsonSchema(t.schema) - }; - case "bedrock": return { toolSpec: { - name: t.name, - description: t.description, - inputSchema: toJsonSchema(t.schema) - } }; - case "google": return { - name: t.name, - description: t.description, - parameters: toJsonSchema(t.schema) - }; - default: throw new Error(`Unsupported tool style: ${this.toolStyle}`); - } +/* harmony default export */ const mustache_mustache = (mustache); + +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/template.js + + + +//#region src/prompts/template.ts +function configureMustache() { + mustache_mustache.escape = (text) => text; +} +const parseFString = (template) => { + const chars = template.split(""); + const nodes = []; + const nextBracket = (bracket, start) => { + for (let i$1 = start; i$1 < chars.length; i$1 += 1) if (bracket.includes(chars[i$1])) return i$1; + return -1; + }; + let i = 0; + while (i < chars.length) if (chars[i] === "{" && i + 1 < chars.length && chars[i + 1] === "{") { + nodes.push({ + type: "literal", + text: "{" }); - const wrapped = this.toolStyle === "google" ? [{ functionDeclarations: toolDicts }] : toolDicts; - const next = new FakeStreamingChatModel({ - sleep: this.sleep, - responses: this.responses, - chunks: this.chunks, - toolStyle: this.toolStyle, - thrownErrorString: this.thrownErrorString + i += 2; + } else if (chars[i] === "}" && i + 1 < chars.length && chars[i + 1] === "}") { + nodes.push({ + type: "literal", + text: "}" }); - next.tools = merged; - return next.withConfig({ tools: wrapped }); - } - async _generate(messages, _options, _runManager) { - if (this.thrownErrorString) throw new Error(this.thrownErrorString); - const content = this.responses?.[0]?.content ?? messages[0].content ?? ""; - const generation = { generations: [{ - text: "", - message: new AIMessage({ - content, - tool_calls: this.chunks?.[0]?.tool_calls - }) - }] }; - return generation; - } - async *_streamResponseChunks(_messages, _options, runManager) { - if (this.thrownErrorString) throw new Error(this.thrownErrorString); - if (this.chunks?.length) { - for (const msgChunk of this.chunks) { - const cg = new ChatGenerationChunk({ - message: new AIMessageChunk({ - content: msgChunk.content, - tool_calls: msgChunk.tool_calls, - additional_kwargs: msgChunk.additional_kwargs ?? {} - }), - text: msgChunk.content?.toString() ?? "" - }); - yield cg; - await runManager?.handleLLMNewToken(msgChunk.content, void 0, void 0, void 0, void 0, { chunk: cg }); - } - return; - } - const fallback = this.responses?.[0] ?? new AIMessage(typeof _messages[0].content === "string" ? _messages[0].content : ""); - const text = typeof fallback.content === "string" ? fallback.content : ""; - for (const ch of text) { - await new Promise((r) => setTimeout(r, this.sleep)); - const cg = new ChatGenerationChunk({ - message: new AIMessageChunk({ content: ch }), - text: ch - }); - yield cg; - await runManager?.handleLLMNewToken(ch, void 0, void 0, void 0, void 0, { chunk: cg }); - } - } -}; -/** -* A fake Chat Model that returns a predefined list of responses. It can be used -* for testing purposes. -* @example -* ```typescript -* const chat = new FakeListChatModel({ -* responses: ["I'll callback later.", "You 'console' them!"] -* }); -* -* const firstMessage = new HumanMessage("You want to hear a JavaScript joke?"); -* const secondMessage = new HumanMessage("How do you cheer up a JavaScript developer?"); -* -* // Call the chat model with a message and log the response -* const firstResponse = await chat.call([firstMessage]); -* console.log({ firstResponse }); -* -* const secondResponse = await chat.call([secondMessage]); -* console.log({ secondResponse }); -* ``` -*/ -var FakeListChatModel = class extends BaseChatModel { - static lc_name() { - return "FakeListChatModel"; - } - lc_serializable = true; - responses; - i = 0; - sleep; - emitCustomEvent = false; - constructor(params) { - super(params); - const { responses, sleep, emitCustomEvent } = params; - this.responses = responses; - this.sleep = sleep; - this.emitCustomEvent = emitCustomEvent ?? this.emitCustomEvent; - } - _combineLLMOutput() { - return []; - } - _llmType() { - return "fake-list"; - } - async _generate(_messages, options, runManager) { - await this._sleepIfRequested(); - if (options?.thrownErrorString) throw new Error(options.thrownErrorString); - if (this.emitCustomEvent) await runManager?.handleCustomEvent("some_test_event", { someval: true }); - if (options?.stop?.length) return { generations: [this._formatGeneration(options.stop[0])] }; - else { - const response = this._currentResponse(); - this._incrementResponse(); - return { - generations: [this._formatGeneration(response)], - llmOutput: {} - }; - } - } - _formatGeneration(text) { - return { - message: new AIMessage(text), - text - }; - } - async *_streamResponseChunks(_messages, options, runManager) { - const response = this._currentResponse(); - this._incrementResponse(); - if (this.emitCustomEvent) await runManager?.handleCustomEvent("some_test_event", { someval: true }); - for await (const text of response) { - await this._sleepIfRequested(); - if (options?.thrownErrorString) throw new Error(options.thrownErrorString); - const chunk = this._createResponseChunk(text); - yield chunk; - runManager?.handleLLMNewToken(text); - } - } - async _sleepIfRequested() { - if (this.sleep !== void 0) await this._sleep(); - } - async _sleep() { - return new Promise((resolve) => { - setTimeout(() => resolve(), this.sleep); + i += 2; + } else if (chars[i] === "{") { + const j = nextBracket("}", i); + if (j < 0) throw new Error("Unclosed '{' in template."); + nodes.push({ + type: "variable", + name: chars.slice(i + 1, j).join("") }); - } - _createResponseChunk(text) { - return new ChatGenerationChunk({ - message: new AIMessageChunk({ content: text }), + i = j + 1; + } else if (chars[i] === "}") throw new Error("Single '}' in template."); + else { + const next = nextBracket("{}", i); + const text = (next < 0 ? chars.slice(i) : chars.slice(i, next)).join(""); + nodes.push({ + type: "literal", text }); + i = next < 0 ? chars.length : next; } - _currentResponse() { - return this.responses[this.i]; - } - _incrementResponse() { - if (this.i < this.responses.length - 1) this.i += 1; - else this.i = 0; - } - withStructuredOutput(_params, _config) { - return RunnableLambda.from(async (input) => { - const message = await this.invoke(input); - if (message.tool_calls?.[0]?.args) return message.tool_calls[0].args; - if (typeof message.content === "string") return JSON.parse(message.content); - throw new Error("No structured output found"); - }); - } + return nodes; }; - -//#endregion - -//# sourceMappingURL=chat_models.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/embeddings.js - - -//#region src/utils/testing/embeddings.ts /** -* A class that provides synthetic embeddings by overriding the -* embedDocuments and embedQuery methods to generate embeddings based on -* the input documents. The embeddings are generated by converting each -* document into chunks, calculating a numerical value for each chunk, and -* returning an array of these values as the embedding. +* Convert the result of mustache.parse into an array of ParsedTemplateNode, +* to make it compatible with other LangChain string parsing template formats. +* +* @param {mustache.TemplateSpans} template The result of parsing a mustache template with the mustache.js library. +* @param {string[]} context Array of section variable names for nested context +* @returns {ParsedTemplateNode[]} */ -var SyntheticEmbeddings = class extends Embeddings { - vectorSize; - constructor(params) { - super(params ?? {}); - this.vectorSize = params?.vectorSize ?? 4; - } - /** - * Generates synthetic embeddings for a list of documents. - * @param documents List of documents to generate embeddings for. - * @returns A promise that resolves with a list of synthetic embeddings for each document. - */ - async embedDocuments(documents) { - return Promise.all(documents.map((doc) => this.embedQuery(doc))); - } - /** - * Generates a synthetic embedding for a document. The document is - * converted into chunks, a numerical value is calculated for each chunk, - * and an array of these values is returned as the embedding. - * @param document The document to generate an embedding for. - * @returns A promise that resolves with a synthetic embedding for the document. - */ - async embedQuery(document) { - let doc = document; - doc = doc.toLowerCase().replaceAll(/[^a-z ]/g, ""); - const padMod = doc.length % this.vectorSize; - const padGapSize = padMod === 0 ? 0 : this.vectorSize - padMod; - const padSize = doc.length + padGapSize; - doc = doc.padEnd(padSize, " "); - const chunkSize = doc.length / this.vectorSize; - const docChunk = []; - for (let co = 0; co < doc.length; co += chunkSize) docChunk.push(doc.slice(co, co + chunkSize)); - const ret = docChunk.map((s) => { - let sum = 0; - for (let co = 0; co < s.length; co += 1) sum += s === " " ? 0 : s.charCodeAt(co); - const ret$1 = sum % 26 / 26; - return ret$1; +const mustacheTemplateToNodes = (template, context = []) => { + const nodes = []; + for (const temp of template) if (temp[0] === "name") { + const name = temp[1].includes(".") ? temp[1].split(".")[0] : temp[1]; + nodes.push({ + type: "variable", + name }); - return ret; - } -}; -/** -* A class that provides fake embeddings by overriding the embedDocuments -* and embedQuery methods to return fixed values. -*/ -var FakeEmbeddings = class extends Embeddings { - constructor(params) { - super(params ?? {}); - } - /** - * Generates fixed embeddings for a list of documents. - * @param documents List of documents to generate embeddings for. - * @returns A promise that resolves with a list of fixed embeddings for each document. - */ - embedDocuments(documents) { - return Promise.resolve(documents.map(() => [ - .1, - .2, - .3, - .4 - ])); - } - /** - * Generates a fixed embedding for a query. - * @param _ The query to generate an embedding for. - * @returns A promise that resolves with a fixed embedding for the query. - */ - embedQuery(_) { - return Promise.resolve([ - .1, - .2, - .3, - .4 - ]); - } -}; - -//#endregion - -//# sourceMappingURL=embeddings.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/llms.js - - -//#region src/utils/testing/llms.ts -var FakeLLM = class extends LLM { - response; - thrownErrorString; - constructor(fields) { - super(fields); - this.response = fields.response; - this.thrownErrorString = fields.thrownErrorString; - } - _llmType() { - return "fake"; - } - async _call(prompt, _options, runManager) { - if (this.thrownErrorString) throw new Error(this.thrownErrorString); - const response = this.response ?? prompt; - await runManager?.handleLLMNewToken(response); - return response; - } + } else if ([ + "#", + "&", + "^", + ">" + ].includes(temp[0])) { + nodes.push({ + type: "variable", + name: temp[1] + }); + if (temp[0] === "#" && temp.length > 4 && Array.isArray(temp[4])) { + const newContext = [...context, temp[1]]; + const nestedNodes = mustacheTemplateToNodes(temp[4], newContext); + nodes.push(...nestedNodes); + } + } else nodes.push({ + type: "literal", + text: temp[1] + }); + return nodes; }; -var FakeStreamingLLM = class extends LLM { - sleep = 50; - responses; - thrownErrorString; - constructor(fields) { - super(fields); - this.sleep = fields.sleep ?? this.sleep; - this.responses = fields.responses; - this.thrownErrorString = fields.thrownErrorString; - } - _llmType() { - return "fake"; - } - async _call(prompt) { - if (this.thrownErrorString) throw new Error(this.thrownErrorString); - const response = this.responses?.[0]; - this.responses = this.responses?.slice(1); - return response ?? prompt; - } - async *_streamResponseChunks(input, _options, runManager) { - if (this.thrownErrorString) throw new Error(this.thrownErrorString); - const response = this.responses?.[0]; - this.responses = this.responses?.slice(1); - for (const c of response ?? input) { - await new Promise((resolve) => setTimeout(resolve, this.sleep)); - yield { - text: c, - generationInfo: {} - }; - await runManager?.handleLLMNewToken(c); +const parseMustache = (template) => { + configureMustache(); + const parsed = mustache_mustache.parse(template); + return mustacheTemplateToNodes(parsed); +}; +const interpolateFString = (template, values) => { + return parseFString(template).reduce((res, node) => { + if (node.type === "variable") { + if (node.name in values) { + const stringValue = typeof values[node.name] === "string" ? values[node.name] : JSON.stringify(values[node.name]); + return res + stringValue; + } + throw new Error(`(f-string) Missing value for input ${node.name}`); } - } + return res + node.text; + }, ""); }; - -//#endregion - -//# sourceMappingURL=llms.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/message_history.js - - - - - - -//#region src/utils/testing/message_history.ts -var FakeChatMessageHistory = class extends BaseChatMessageHistory { - lc_namespace = [ - "langchain_core", - "message", - "fake" - ]; - messages = []; - constructor() { - super(); - } - async getMessages() { - return this.messages; - } - async addMessage(message) { - this.messages.push(message); - } - async addUserMessage(message) { - this.messages.push(new HumanMessage(message)); - } - async addAIMessage(message) { - this.messages.push(new AIMessage(message)); - } - async clear() { - this.messages = []; - } +const interpolateMustache = (template, values) => { + configureMustache(); + return mustache_mustache.render(template, values); }; -var FakeListChatMessageHistory = class extends BaseListChatMessageHistory { - lc_namespace = [ - "langchain_core", - "message", - "fake" - ]; - messages = []; - constructor() { - super(); - } - async addMessage(message) { - this.messages.push(message); - } - async getMessages() { - return this.messages; +const DEFAULT_FORMATTER_MAPPING = { + "f-string": interpolateFString, + mustache: interpolateMustache +}; +const DEFAULT_PARSER_MAPPING = { + "f-string": parseFString, + mustache: parseMustache +}; +const renderTemplate = (template, templateFormat, inputValues) => { + try { + return DEFAULT_FORMATTER_MAPPING[templateFormat](template, inputValues); + } catch (e) { + const error = addLangChainErrorFields(e, "INVALID_PROMPT_INPUT"); + throw error; } }; -var FakeTracer = class extends BaseTracer { - name = "fake_tracer"; - runs = []; - constructor() { - super(); +const template_parseTemplate = (template, templateFormat) => DEFAULT_PARSER_MAPPING[templateFormat](template); +const checkValidTemplate = (template, templateFormat, inputVariables) => { + if (!(templateFormat in DEFAULT_FORMATTER_MAPPING)) { + const validFormats = Object.keys(DEFAULT_FORMATTER_MAPPING); + throw new Error(`Invalid template format. Got \`${templateFormat}\`; + should be one of ${validFormats}`); } - persistRun(run) { - this.runs.push(run); - return Promise.resolve(); + try { + const dummyInputs = Object.fromEntries(inputVariables.map((v) => [v, "foo"])); + if (Array.isArray(template)) template.forEach((message) => { + if (message.type === "text" && "text" in message && typeof message.text === "string") renderTemplate(message.text, templateFormat, dummyInputs); + else if (message.type === "image_url") { + if (typeof message.image_url === "string") renderTemplate(message.image_url, templateFormat, dummyInputs); + else if (typeof message.image_url === "object" && message.image_url !== null && "url" in message.image_url && typeof message.image_url.url === "string") { + const imageUrl = message.image_url.url; + renderTemplate(imageUrl, templateFormat, dummyInputs); + } + } else throw new Error(`Invalid message template received. ${JSON.stringify(message, null, 2)}`); + }); + else renderTemplate(template, templateFormat, dummyInputs); + } catch (e) { + throw new Error(`Invalid prompt schema: ${e.message}`); } }; //#endregion -//# sourceMappingURL=message_history.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/output_parsers.js +//# sourceMappingURL=template.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/prompt.js -//#region src/utils/testing/output_parsers.ts + +//#region src/prompts/prompt.ts /** -* Parser for comma-separated values. It splits the input text by commas -* and trims the resulting values. +* Schema to represent a basic prompt for an LLM. +* @augments BasePromptTemplate +* @augments PromptTemplateInput +* +* @example +* ```ts +* import { PromptTemplate } from "langchain/prompts"; +* +* const prompt = new PromptTemplate({ +* inputVariables: ["foo"], +* template: "Say {foo}", +* }); +* ``` */ -var FakeSplitIntoListParser = class extends BaseOutputParser { - lc_namespace = ["tests", "fake"]; - getFormatInstructions() { - return ""; +var PromptTemplate = class PromptTemplate extends BaseStringPromptTemplate { + static lc_name() { + return "PromptTemplate"; } - async parse(text) { - return text.split(",").map((value) => value.trim()); + template; + templateFormat = "f-string"; + validateTemplate = true; + /** + * Additional fields which should be included inside + * the message content array if using a complex message + * content. + */ + additionalContentFields; + constructor(input) { + super(input); + if (input.templateFormat === "mustache" && input.validateTemplate === void 0) this.validateTemplate = false; + Object.assign(this, input); + if (this.validateTemplate) { + if (this.templateFormat === "mustache") throw new Error("Mustache templates cannot be validated."); + let totalInputVariables = this.inputVariables; + if (this.partialVariables) totalInputVariables = totalInputVariables.concat(Object.keys(this.partialVariables)); + checkValidTemplate(this.template, this.templateFormat, totalInputVariables); + } } -}; - -//#endregion - -//# sourceMappingURL=output_parsers.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/retrievers.js - - - -//#region src/utils/testing/retrievers.ts -var FakeRetriever = class extends BaseRetriever { - lc_namespace = ["test", "fake"]; - output = [new Document({ pageContent: "foo" }), new Document({ pageContent: "bar" })]; - constructor(fields) { - super(); - this.output = fields?.output ?? this.output; + _getPromptType() { + return "prompt"; } - async _getRelevantDocuments(_query) { - return this.output; + /** + * Formats the prompt template with the provided values. + * @param values The values to be used to format the prompt template. + * @returns A promise that resolves to a string which is the formatted prompt. + */ + async format(values) { + const allValues = await this.mergePartialAndUserVariables(values); + return renderTemplate(this.template, this.templateFormat, allValues); } -}; - -//#endregion - -//# sourceMappingURL=retrievers.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/runnables.js - - -//#region src/utils/testing/runnables.ts -var FakeRunnable = class extends Runnable { - lc_namespace = ["tests", "fake"]; - returnOptions; - constructor(fields) { - super(fields); - this.returnOptions = fields.returnOptions; + /** + * Take examples in list format with prefix and suffix to create a prompt. + * + * Intended to be used a a way to dynamically create a prompt from examples. + * + * @param examples - List of examples to use in the prompt. + * @param suffix - String to go after the list of examples. Should generally set up the user's input. + * @param inputVariables - A list of variable names the final prompt template will expect + * @param exampleSeparator - The separator to use in between examples + * @param prefix - String that should go before any examples. Generally includes examples. + * + * @returns The final prompt template generated. + */ + static fromExamples(examples, suffix, inputVariables, exampleSeparator = "\n\n", prefix = "") { + const template = [ + prefix, + ...examples, + suffix + ].join(exampleSeparator); + return new PromptTemplate({ + inputVariables, + template + }); } - async invoke(input, options) { - if (this.returnOptions) return options ?? {}; - return { input }; + static fromTemplate(template, options) { + const { templateFormat = "f-string",...rest } = options ?? {}; + const names = /* @__PURE__ */ new Set(); + template_parseTemplate(template, templateFormat).forEach((node) => { + if (node.type === "variable") names.add(node.name); + }); + return new PromptTemplate({ + inputVariables: [...names], + templateFormat, + template, + ...rest + }); } -}; - -//#endregion - -//# sourceMappingURL=runnables.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/tools.js - - -//#region src/utils/testing/tools.ts -var FakeTool = class extends StructuredTool { - name; - description; - schema; - constructor(fields) { - super(fields); - this.name = fields.name; - this.description = fields.description; - this.schema = fields.schema; + /** + * Partially applies values to the prompt template. + * @param values The values to be partially applied to the prompt template. + * @returns A new instance of PromptTemplate with the partially applied values. + */ + async partial(values) { + const newInputVariables = this.inputVariables.filter((iv) => !(iv in values)); + const newPartialVariables = { + ...this.partialVariables ?? {}, + ...values + }; + const promptDict = { + ...this, + inputVariables: newInputVariables, + partialVariables: newPartialVariables + }; + return new PromptTemplate(promptDict); } - async _call(arg, _runManager) { - return JSON.stringify(arg); + serialize() { + if (this.outputParser !== void 0) throw new Error("Cannot serialize a prompt template with an output parser"); + return { + _type: this._getPromptType(), + input_variables: this.inputVariables, + template: this.template, + template_format: this.templateFormat + }; } -}; - -//#endregion - -//# sourceMappingURL=tools.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/tracers.js - - -//#region src/utils/testing/tracers.ts -var SingleRunExtractor = class extends BaseTracer { - runPromiseResolver; - runPromise; - /** The name of the callback handler. */ - name = "single_run_extractor"; - constructor() { - super(); - this.runPromise = new Promise((extract) => { - this.runPromiseResolver = extract; + static async deserialize(data) { + if (!data.template) throw new Error("Prompt template must have a template"); + const res = new PromptTemplate({ + inputVariables: data.input_variables, + template: data.template, + templateFormat: data.template_format }); - } - async persistRun(run) { - this.runPromiseResolver(run); - } - async extract() { - return this.runPromise; + return res; } }; //#endregion -//# sourceMappingURL=tracers.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/ml-distance/similarities.js -//#region src/utils/ml-distance/similarities.ts -/** -* Returns the average of cosine distances between vectors a and b -* @param a - first vector -* @param b - second vector -* -*/ -function cosine(a, b) { - let p = 0; - let p2 = 0; - let q2 = 0; - for (let i = 0; i < a.length; i++) { - p += a[i] * b[i]; - p2 += a[i] * a[i]; - q2 += b[i] * b[i]; - } - return p / (Math.sqrt(p2) * Math.sqrt(q2)); -} - -//#endregion - -//# sourceMappingURL=similarities.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/vectorstores.js +//# sourceMappingURL=prompt.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/image.js -//#region src/utils/testing/vectorstores.ts +//#region src/prompts/image.ts /** -* Class that extends `VectorStore` to store vectors in memory. Provides -* methods for adding documents, performing similarity searches, and -* creating instances from texts, documents, or an existing index. +* An image prompt template for a multimodal model. */ -var FakeVectorStore = class FakeVectorStore extends VectorStore { - memoryVectors = []; - similarity; - _vectorstoreType() { - return "memory"; - } - constructor(embeddings, { similarity,...rest } = {}) { - super(embeddings, rest); - this.similarity = similarity ?? cosine; +var ImagePromptTemplate = class ImagePromptTemplate extends BasePromptTemplate { + static lc_name() { + return "ImagePromptTemplate"; } + lc_namespace = [ + "langchain_core", + "prompts", + "image" + ]; + template; + templateFormat = "f-string"; + validateTemplate = true; /** - * Method to add documents to the memory vector store. It extracts the - * text from each document, generates embeddings for them, and adds the - * resulting vectors to the store. - * @param documents Array of `Document` instances to be added to the store. - * @returns Promise that resolves when all documents have been added. + * Additional fields which should be included inside + * the message content array if using a complex message + * content. */ - async addDocuments(documents) { - const texts = documents.map(({ pageContent }) => pageContent); - return this.addVectors(await this.embeddings.embedDocuments(texts), documents); + additionalContentFields; + constructor(input) { + super(input); + this.template = input.template; + this.templateFormat = input.templateFormat ?? this.templateFormat; + this.validateTemplate = input.validateTemplate ?? this.validateTemplate; + this.additionalContentFields = input.additionalContentFields; + if (this.validateTemplate) { + let totalInputVariables = this.inputVariables; + if (this.partialVariables) totalInputVariables = totalInputVariables.concat(Object.keys(this.partialVariables)); + checkValidTemplate([{ + type: "image_url", + image_url: this.template + }], this.templateFormat, totalInputVariables); + } } - /** - * Method to add vectors to the memory vector store. It creates - * `MemoryVector` instances for each vector and document pair and adds - * them to the store. - * @param vectors Array of vectors to be added to the store. - * @param documents Array of `Document` instances corresponding to the vectors. - * @returns Promise that resolves when all vectors have been added. - */ - async addVectors(vectors, documents) { - const memoryVectors = vectors.map((embedding, idx) => ({ - content: documents[idx].pageContent, - embedding, - metadata: documents[idx].metadata - })); - this.memoryVectors = this.memoryVectors.concat(memoryVectors); + _getPromptType() { + return "prompt"; } /** - * Method to perform a similarity search in the memory vector store. It - * calculates the similarity between the query vector and each vector in - * the store, sorts the results by similarity, and returns the top `k` - * results along with their scores. - * @param query Query vector to compare against the vectors in the store. - * @param k Number of top results to return. - * @param filter Optional filter function to apply to the vectors before performing the search. - * @returns Promise that resolves with an array of tuples, each containing a `Document` and its similarity score. + * Partially applies values to the prompt template. + * @param values The values to be partially applied to the prompt template. + * @returns A new instance of ImagePromptTemplate with the partially applied values. */ - async similaritySearchVectorWithScore(query, k, filter) { - const filterFunction = (memoryVector) => { - if (!filter) return true; - const doc = new Document({ - metadata: memoryVector.metadata, - pageContent: memoryVector.content - }); - return filter(doc); + async partial(values) { + const newInputVariables = this.inputVariables.filter((iv) => !(iv in values)); + const newPartialVariables = { + ...this.partialVariables ?? {}, + ...values }; - const filteredMemoryVectors = this.memoryVectors.filter(filterFunction); - const searches = filteredMemoryVectors.map((vector, index) => ({ - similarity: this.similarity(query, vector.embedding), - index - })).sort((a, b) => a.similarity > b.similarity ? -1 : 0).slice(0, k); - const result = searches.map((search) => [new Document({ - metadata: filteredMemoryVectors[search.index].metadata, - pageContent: filteredMemoryVectors[search.index].content - }), search.similarity]); - return result; - } - /** - * Static method to create a `FakeVectorStore` instance from an array of - * texts. It creates a `Document` for each text and metadata pair, and - * adds them to the store. - * @param texts Array of texts to be added to the store. - * @param metadatas Array or single object of metadata corresponding to the texts. - * @param embeddings `Embeddings` instance used to generate embeddings for the texts. - * @param dbConfig Optional `FakeVectorStoreArgs` to configure the `FakeVectorStore` instance. - * @returns Promise that resolves with a new `FakeVectorStore` instance. - */ - static async fromTexts(texts, metadatas, embeddings, dbConfig) { - const docs = []; - for (let i = 0; i < texts.length; i += 1) { - const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas; - const newDoc = new Document({ - pageContent: texts[i], - metadata - }); - docs.push(newDoc); - } - return FakeVectorStore.fromDocuments(docs, embeddings, dbConfig); + const promptDict = { + ...this, + inputVariables: newInputVariables, + partialVariables: newPartialVariables + }; + return new ImagePromptTemplate(promptDict); } /** - * Static method to create a `FakeVectorStore` instance from an array of - * `Document` instances. It adds the documents to the store. - * @param docs Array of `Document` instances to be added to the store. - * @param embeddings `Embeddings` instance used to generate embeddings for the documents. - * @param dbConfig Optional `FakeVectorStoreArgs` to configure the `FakeVectorStore` instance. - * @returns Promise that resolves with a new `FakeVectorStore` instance. + * Formats the prompt template with the provided values. + * @param values The values to be used to format the prompt template. + * @returns A promise that resolves to a string which is the formatted prompt. */ - static async fromDocuments(docs, embeddings, dbConfig) { - const instance = new this(embeddings, dbConfig); - await instance.addDocuments(docs); - return instance; + async format(values) { + const formatted = {}; + for (const [key, value] of Object.entries(this.template)) if (typeof value === "string") formatted[key] = renderTemplate(value, this.templateFormat, values); + else formatted[key] = value; + const url = values.url || formatted.url; + const detail = values.detail || formatted.detail; + if (!url) throw new Error("Must provide either an image URL."); + if (typeof url !== "string") throw new Error("url must be a string."); + const output = { url }; + if (detail) output.detail = detail; + return output; } /** - * Static method to create a `FakeVectorStore` instance from an existing - * index. It creates a new `FakeVectorStore` instance without adding any - * documents or vectors. - * @param embeddings `Embeddings` instance used to generate embeddings for the documents. - * @param dbConfig Optional `FakeVectorStoreArgs` to configure the `FakeVectorStore` instance. - * @returns Promise that resolves with a new `FakeVectorStore` instance. - */ - static async fromExistingIndex(embeddings, dbConfig) { - const instance = new this(embeddings, dbConfig); - return instance; + * Formats the prompt given the input values and returns a formatted + * prompt value. + * @param values The input values to format the prompt. + * @returns A Promise that resolves to a formatted prompt value. + */ + async formatPromptValue(values) { + const formattedPrompt = await this.format(values); + return new ImagePromptValue(formattedPrompt); } }; //#endregion -//# sourceMappingURL=vectorstores.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/index.js +//# sourceMappingURL=image.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/dict.js +//#region src/prompts/dict.ts +var DictPromptTemplate = class extends Runnable { + lc_namespace = [ + "langchain_core", + "prompts", + "dict" + ]; + lc_serializable = true; + template; + templateFormat; + inputVariables; + static lc_name() { + return "DictPromptTemplate"; + } + constructor(fields) { + const templateFormat = fields.templateFormat ?? "f-string"; + const inputVariables = _getInputVariables(fields.template, templateFormat); + super({ + inputVariables, + ...fields + }); + this.template = fields.template; + this.templateFormat = templateFormat; + this.inputVariables = inputVariables; + } + async format(values) { + return _insertInputVariables(this.template, values, this.templateFormat); + } + async invoke(values) { + return await this._callWithConfig(this.format.bind(this), values, { runType: "prompt" }); + } +}; +function _getInputVariables(template, templateFormat) { + const inputVariables = []; + for (const v of Object.values(template)) if (typeof v === "string") template_parseTemplate(v, templateFormat).forEach((t) => { + if (t.type === "variable") inputVariables.push(t.name); + }); + else if (Array.isArray(v)) { + for (const x of v) if (typeof x === "string") template_parseTemplate(x, templateFormat).forEach((t) => { + if (t.type === "variable") inputVariables.push(t.name); + }); + else if (typeof x === "object") inputVariables.push(..._getInputVariables(x, templateFormat)); + } else if (typeof v === "object" && v !== null) inputVariables.push(..._getInputVariables(v, templateFormat)); + return Array.from(new Set(inputVariables)); +} +function _insertInputVariables(template, inputs, templateFormat) { + const formatted = {}; + for (const [k, v] of Object.entries(template)) if (typeof v === "string") formatted[k] = renderTemplate(v, templateFormat, inputs); + else if (Array.isArray(v)) { + const formattedV = []; + for (const x of v) if (typeof x === "string") formattedV.push(renderTemplate(x, templateFormat, inputs)); + else if (typeof x === "object") formattedV.push(_insertInputVariables(x, inputs, templateFormat)); + formatted[k] = formattedV; + } else if (typeof v === "object" && v !== null) formatted[k] = _insertInputVariables(v, inputs, templateFormat); + else formatted[k] = v; + return formatted; +} +//#endregion +//# sourceMappingURL=dict.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/chat.js @@ -82488,2190 +74700,3288 @@ var FakeVectorStore = class FakeVectorStore extends VectorStore { -//#region src/utils/testing/index.ts -var testing_exports = {}; -__export(testing_exports, { - FakeChatMessageHistory: () => FakeChatMessageHistory, - FakeChatModel: () => FakeChatModel, - FakeEmbeddings: () => FakeEmbeddings, - FakeLLM: () => FakeLLM, - FakeListChatMessageHistory: () => FakeListChatMessageHistory, - FakeListChatModel: () => FakeListChatModel, - FakeRetriever: () => FakeRetriever, - FakeRunnable: () => FakeRunnable, - FakeSplitIntoListParser: () => FakeSplitIntoListParser, - FakeStreamingChatModel: () => FakeStreamingChatModel, - FakeStreamingLLM: () => FakeStreamingLLM, - FakeTool: () => FakeTool, - FakeTracer: () => FakeTracer, - FakeVectorStore: () => FakeVectorStore, - SingleRunExtractor: () => SingleRunExtractor, - SyntheticEmbeddings: () => SyntheticEmbeddings -}); -//#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/types/index.js -//#region src/utils/types/index.ts -var types_exports = {}; -__export(types_exports, { - extendInteropZodObject: () => extendInteropZodObject, - getInteropZodDefaultGetter: () => getInteropZodDefaultGetter, - getInteropZodObjectShape: () => getInteropZodObjectShape, - getSchemaDescription: () => getSchemaDescription, - interopParse: () => interopParse, - interopParseAsync: () => interopParseAsync, - interopSafeParse: () => interopSafeParse, - interopSafeParseAsync: () => interopSafeParseAsync, - interopZodObjectMakeFieldsOptional: () => interopZodObjectMakeFieldsOptional, - interopZodObjectPartial: () => interopZodObjectPartial, - interopZodObjectPassthrough: () => interopZodObjectPassthrough, - interopZodObjectStrict: () => interopZodObjectStrict, - interopZodTransformInputSchema: () => interopZodTransformInputSchema, - isInteropZodError: () => isInteropZodError, - isInteropZodLiteral: () => isInteropZodLiteral, - isInteropZodObject: () => isInteropZodObject, - isInteropZodSchema: () => isInteropZodSchema, - isShapelessZodSchema: () => isShapelessZodSchema, - isSimpleStringZodSchema: () => isSimpleStringZodSchema, - isZodArrayV4: () => isZodArrayV4, - isZodLiteralV3: () => isZodLiteralV3, - isZodLiteralV4: () => isZodLiteralV4, - isZodObjectV3: () => isZodObjectV3, - isZodObjectV4: () => isZodObjectV4, - isZodSchema: () => isZodSchema, - isZodSchemaV3: () => isZodSchemaV3, - isZodSchemaV4: () => isZodSchemaV4 -}); -//#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/event_source_parse.js -//#region src/utils/event_source_parse.ts -var event_source_parse_exports = {}; -__export(event_source_parse_exports, { - EventStreamContentType: () => EventStreamContentType, - convertEventStreamToIterableReadableDataStream: () => convertEventStreamToIterableReadableDataStream, - getBytes: () => getBytes, - getLines: () => getLines, - getMessages: () => getMessages -}); -const EventStreamContentType = "text/event-stream"; +//#region src/prompts/chat.ts /** -* Converts a ReadableStream into a callback pattern. -* @param stream The input ReadableStream. -* @param onChunk A function that will be called on each new byte chunk in the stream. -* @returns {Promise} A promise that will be resolved when the stream closes. +* Abstract class that serves as a base for creating message prompt +* templates. It defines how to format messages for different roles in a +* conversation. */ -async function getBytes(stream, onChunk) { - if (stream instanceof ReadableStream) { - const reader = stream.getReader(); - while (true) { - const result = await reader.read(); - if (result.done) { - onChunk(new Uint8Array(), true); - break; +var BaseMessagePromptTemplate = class extends Runnable { + lc_namespace = [ + "langchain_core", + "prompts", + "chat" + ]; + lc_serializable = true; + /** + * Calls the formatMessages method with the provided input and options. + * @param input Input for the formatMessages method + * @param options Optional BaseCallbackConfig + * @returns Formatted output messages + */ + async invoke(input, options) { + return this._callWithConfig((input$1) => this.formatMessages(input$1), input, { + ...options, + runType: "prompt" + }); + } +}; +/** +* Class that represents a placeholder for messages in a chat prompt. It +* extends the BaseMessagePromptTemplate. +*/ +var MessagesPlaceholder = class extends BaseMessagePromptTemplate { + static lc_name() { + return "MessagesPlaceholder"; + } + variableName; + optional; + constructor(fields) { + if (typeof fields === "string") fields = { variableName: fields }; + super(fields); + this.variableName = fields.variableName; + this.optional = fields.optional ?? false; + } + get inputVariables() { + return [this.variableName]; + } + async formatMessages(values) { + const input = values[this.variableName]; + if (this.optional && !input) return []; + else if (!input) { + const error = /* @__PURE__ */ new Error(`Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages as an input value. Received: undefined`); + error.name = "InputFormatError"; + throw error; + } + let formattedMessages; + try { + if (Array.isArray(input)) formattedMessages = input.map(utils_coerceMessageLikeToMessage); + else formattedMessages = [utils_coerceMessageLikeToMessage(input)]; + } catch (e) { + const readableInput = typeof input === "string" ? input : JSON.stringify(input, null, 2); + const error = new Error([ + `Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages or coerceable values as input.`, + `Received value: ${readableInput}`, + `Additional message: ${e.message}` + ].join("\n\n")); + error.name = "InputFormatError"; + error.lc_error_code = e.lc_error_code; + throw error; + } + return formattedMessages; + } +}; +/** +* Abstract class that serves as a base for creating message string prompt +* templates. It extends the BaseMessagePromptTemplate. +*/ +var BaseMessageStringPromptTemplate = class extends BaseMessagePromptTemplate { + prompt; + constructor(fields) { + if (!("prompt" in fields)) fields = { prompt: fields }; + super(fields); + this.prompt = fields.prompt; + } + get inputVariables() { + return this.prompt.inputVariables; + } + async formatMessages(values) { + return [await this.format(values)]; + } +}; +/** +* Abstract class that serves as a base for creating chat prompt +* templates. It extends the BasePromptTemplate. +*/ +var BaseChatPromptTemplate = class extends BasePromptTemplate { + constructor(input) { + super(input); + } + async format(values) { + return (await this.formatPromptValue(values)).toString(); + } + async formatPromptValue(values) { + const resultMessages = await this.formatMessages(values); + return new ChatPromptValue(resultMessages); + } +}; +/** +* Class that represents a chat message prompt template. It extends the +* BaseMessageStringPromptTemplate. +*/ +var ChatMessagePromptTemplate = class extends BaseMessageStringPromptTemplate { + static lc_name() { + return "ChatMessagePromptTemplate"; + } + role; + constructor(fields, role) { + if (!("prompt" in fields)) fields = { + prompt: fields, + role + }; + super(fields); + this.role = fields.role; + } + async format(values) { + return new ChatMessage(await this.prompt.format(values), this.role); + } + static fromTemplate(template, role, options) { + return new this(PromptTemplate.fromTemplate(template, { templateFormat: options?.templateFormat }), role); + } +}; +function isTextTemplateParam(param) { + if (param === null || typeof param !== "object" || Array.isArray(param)) return false; + return Object.keys(param).length === 1 && "text" in param && typeof param.text === "string"; +} +function isImageTemplateParam(param) { + if (param === null || typeof param !== "object" || Array.isArray(param)) return false; + return "image_url" in param && (typeof param.image_url === "string" || typeof param.image_url === "object" && param.image_url !== null && "url" in param.image_url && typeof param.image_url.url === "string"); +} +var _StringImageMessagePromptTemplate = class extends BaseMessagePromptTemplate { + lc_namespace = [ + "langchain_core", + "prompts", + "chat" + ]; + lc_serializable = true; + inputVariables = []; + additionalOptions = {}; + prompt; + messageClass; + static _messageClass() { + throw new Error("Can not invoke _messageClass from inside _StringImageMessagePromptTemplate"); + } + chatMessageClass; + constructor(fields, additionalOptions) { + if (!("prompt" in fields)) fields = { prompt: fields }; + super(fields); + this.prompt = fields.prompt; + if (Array.isArray(this.prompt)) { + let inputVariables = []; + this.prompt.forEach((prompt) => { + if ("inputVariables" in prompt) inputVariables = inputVariables.concat(prompt.inputVariables); + }); + this.inputVariables = inputVariables; + } else this.inputVariables = this.prompt.inputVariables; + this.additionalOptions = additionalOptions ?? this.additionalOptions; + } + createMessage(content) { + const constructor = this.constructor; + if (constructor._messageClass()) { + const MsgClass = constructor._messageClass(); + return new MsgClass({ content }); + } else if (constructor.chatMessageClass) { + const MsgClass = constructor.chatMessageClass(); + return new MsgClass({ + content, + role: this.getRoleFromMessageClass(MsgClass.lc_name()) + }); + } else throw new Error("No message class defined"); + } + getRoleFromMessageClass(name) { + switch (name) { + case "HumanMessage": return "human"; + case "AIMessage": return "ai"; + case "SystemMessage": return "system"; + case "ChatMessage": return "chat"; + default: throw new Error("Invalid message class name"); + } + } + static fromTemplate(template, additionalOptions) { + if (typeof template === "string") return new this(PromptTemplate.fromTemplate(template, additionalOptions)); + const prompt = []; + for (const item of template) if (typeof item === "string") prompt.push(PromptTemplate.fromTemplate(item, additionalOptions)); + else if (item === null) {} else if (isTextTemplateParam(item)) { + let text = ""; + if (typeof item.text === "string") text = item.text ?? ""; + const options = { + ...additionalOptions, + additionalContentFields: item + }; + prompt.push(PromptTemplate.fromTemplate(text, options)); + } else if (isImageTemplateParam(item)) { + let imgTemplate = item.image_url ?? ""; + let imgTemplateObject; + let inputVariables = []; + if (typeof imgTemplate === "string") { + let parsedTemplate; + if (additionalOptions?.templateFormat === "mustache") parsedTemplate = parseMustache(imgTemplate); + else parsedTemplate = parseFString(imgTemplate); + const variables = parsedTemplate.flatMap((item$1) => item$1.type === "variable" ? [item$1.name] : []); + if ((variables?.length ?? 0) > 0) { + if (variables.length > 1) throw new Error(`Only one format variable allowed per image template.\nGot: ${variables}\nFrom: ${imgTemplate}`); + inputVariables = [variables[0]]; + } else inputVariables = []; + imgTemplate = { url: imgTemplate }; + imgTemplateObject = new ImagePromptTemplate({ + template: imgTemplate, + inputVariables, + templateFormat: additionalOptions?.templateFormat, + additionalContentFields: item + }); + } else if (typeof imgTemplate === "object") { + if ("url" in imgTemplate) { + let parsedTemplate; + if (additionalOptions?.templateFormat === "mustache") parsedTemplate = parseMustache(imgTemplate.url); + else parsedTemplate = parseFString(imgTemplate.url); + inputVariables = parsedTemplate.flatMap((item$1) => item$1.type === "variable" ? [item$1.name] : []); + } else inputVariables = []; + imgTemplateObject = new ImagePromptTemplate({ + template: imgTemplate, + inputVariables, + templateFormat: additionalOptions?.templateFormat, + additionalContentFields: item + }); + } else throw new Error("Invalid image template"); + prompt.push(imgTemplateObject); + } else if (typeof item === "object") prompt.push(new DictPromptTemplate({ + template: item, + templateFormat: additionalOptions?.templateFormat + })); + return new this({ + prompt, + additionalOptions + }); + } + async format(input) { + if (this.prompt instanceof BaseStringPromptTemplate) { + const text = await this.prompt.format(input); + return this.createMessage(text); + } else { + const content = []; + for (const prompt of this.prompt) { + let inputs = {}; + if (!("inputVariables" in prompt)) throw new Error(`Prompt ${prompt} does not have inputVariables defined.`); + for (const item of prompt.inputVariables) { + if (!inputs) inputs = { [item]: input[item] }; + inputs = { + ...inputs, + [item]: input[item] + }; + } + if (prompt instanceof BaseStringPromptTemplate) { + const formatted = await prompt.format(inputs); + let additionalContentFields; + if ("additionalContentFields" in prompt) additionalContentFields = prompt.additionalContentFields; + if (formatted !== "") content.push({ + ...additionalContentFields, + type: "text", + text: formatted + }); + } else if (prompt instanceof ImagePromptTemplate) { + const formatted = await prompt.format(inputs); + let additionalContentFields; + if ("additionalContentFields" in prompt) additionalContentFields = prompt.additionalContentFields; + content.push({ + ...additionalContentFields, + type: "image_url", + image_url: formatted + }); + } else if (prompt instanceof DictPromptTemplate) { + const formatted = await prompt.format(inputs); + let additionalContentFields; + if ("additionalContentFields" in prompt) additionalContentFields = prompt.additionalContentFields; + content.push({ + ...additionalContentFields, + ...formatted + }); + } } - onChunk(result.value); + return this.createMessage(content); + } + } + async formatMessages(values) { + return [await this.format(values)]; + } +}; +/** +* Class that represents a human message prompt template. It extends the +* BaseMessageStringPromptTemplate. +* @example +* ```typescript +* const message = HumanMessagePromptTemplate.fromTemplate("{text}"); +* const formatted = await message.format({ text: "Hello world!" }); +* +* const chatPrompt = ChatPromptTemplate.fromMessages([message]); +* const formattedChatPrompt = await chatPrompt.invoke({ +* text: "Hello world!", +* }); +* ``` +*/ +var HumanMessagePromptTemplate = class extends _StringImageMessagePromptTemplate { + static _messageClass() { + return HumanMessage; + } + static lc_name() { + return "HumanMessagePromptTemplate"; + } +}; +/** +* Class that represents an AI message prompt template. It extends the +* BaseMessageStringPromptTemplate. +*/ +var AIMessagePromptTemplate = class extends _StringImageMessagePromptTemplate { + static _messageClass() { + return AIMessage; + } + static lc_name() { + return "AIMessagePromptTemplate"; + } +}; +/** +* Class that represents a system message prompt template. It extends the +* BaseMessageStringPromptTemplate. +* @example +* ```typescript +* const message = SystemMessagePromptTemplate.fromTemplate("{text}"); +* const formatted = await message.format({ text: "Hello world!" }); +* +* const chatPrompt = ChatPromptTemplate.fromMessages([message]); +* const formattedChatPrompt = await chatPrompt.invoke({ +* text: "Hello world!", +* }); +* ``` +*/ +var SystemMessagePromptTemplate = class extends _StringImageMessagePromptTemplate { + static _messageClass() { + return SystemMessage; + } + static lc_name() { + return "SystemMessagePromptTemplate"; + } +}; +function _isBaseMessagePromptTemplate(baseMessagePromptTemplateLike) { + return typeof baseMessagePromptTemplateLike.formatMessages === "function"; +} +function _coerceMessagePromptTemplateLike(messagePromptTemplateLike, extra) { + if (_isBaseMessagePromptTemplate(messagePromptTemplateLike) || isBaseMessage(messagePromptTemplateLike)) return messagePromptTemplateLike; + if (Array.isArray(messagePromptTemplateLike) && messagePromptTemplateLike[0] === "placeholder") { + const messageContent = messagePromptTemplateLike[1]; + if (extra?.templateFormat === "mustache" && typeof messageContent === "string" && messageContent.slice(0, 2) === "{{" && messageContent.slice(-2) === "}}") { + const variableName = messageContent.slice(2, -2); + return new MessagesPlaceholder({ + variableName, + optional: true + }); + } else if (typeof messageContent === "string" && messageContent[0] === "{" && messageContent[messageContent.length - 1] === "}") { + const variableName = messageContent.slice(1, -1); + return new MessagesPlaceholder({ + variableName, + optional: true + }); } - } else try { - for await (const chunk of stream) onChunk(new Uint8Array(chunk)); - onChunk(new Uint8Array(), true); - } catch (e) { - throw new Error([ - "Parsing event source stream failed.", - "Ensure your implementation of fetch returns a web or Node readable stream.", - `Error: ${e.message}` - ].join("\n")); + throw new Error(`Invalid placeholder template for format ${extra?.templateFormat ?? `"f-string"`}: "${messagePromptTemplateLike[1]}". Expected a variable name surrounded by ${extra?.templateFormat === "mustache" ? "double" : "single"} curly braces.`); } + const message = utils_coerceMessageLikeToMessage(messagePromptTemplateLike); + let templateData; + if (typeof message.content === "string") templateData = message.content; + else templateData = message.content.map((item) => { + if ("text" in item) return { + ...item, + text: item.text + }; + else if ("image_url" in item) return { + ...item, + image_url: item.image_url + }; + else return item; + }); + if (message._getType() === "human") return HumanMessagePromptTemplate.fromTemplate(templateData, extra); + else if (message._getType() === "ai") return AIMessagePromptTemplate.fromTemplate(templateData, extra); + else if (message._getType() === "system") return SystemMessagePromptTemplate.fromTemplate(templateData, extra); + else if (ChatMessage.isInstance(message)) return ChatMessagePromptTemplate.fromTemplate(message.content, message.role, extra); + else throw new Error(`Could not coerce message prompt template from input. Received message type: "${message._getType()}".`); } -var ControlChars = /* @__PURE__ */ function(ControlChars$1) { - ControlChars$1[ControlChars$1["NewLine"] = 10] = "NewLine"; - ControlChars$1[ControlChars$1["CarriageReturn"] = 13] = "CarriageReturn"; - ControlChars$1[ControlChars$1["Space"] = 32] = "Space"; - ControlChars$1[ControlChars$1["Colon"] = 58] = "Colon"; - return ControlChars$1; -}(ControlChars || {}); -/** -* Parses arbitary byte chunks into EventSource line buffers. -* Each line should be of the format "field: value" and ends with \r, \n, or \r\n. -* @param onLine A function that will be called on each new EventSource line. -* @returns A function that should be called for each incoming byte chunk. -*/ -function getLines(onLine) { - let buffer; - let position; - let fieldLength; - let discardTrailingNewline = false; - return function onChunk(arr, flush) { - if (flush) { - onLine(arr, 0, true); - return; - } - if (buffer === void 0) { - buffer = arr; - position = 0; - fieldLength = -1; - } else buffer = event_source_parse_concat(buffer, arr); - const bufLength = buffer.length; - let lineStart = 0; - while (position < bufLength) { - if (discardTrailingNewline) { - if (buffer[position] === ControlChars.NewLine) lineStart = ++position; - discardTrailingNewline = false; - } - let lineEnd = -1; - for (; position < bufLength && lineEnd === -1; ++position) switch (buffer[position]) { - case ControlChars.Colon: - if (fieldLength === -1) fieldLength = position - lineStart; - break; - case ControlChars.CarriageReturn: discardTrailingNewline = true; - case ControlChars.NewLine: - lineEnd = position; - break; - } - if (lineEnd === -1) break; - onLine(buffer.subarray(lineStart, lineEnd), fieldLength); - lineStart = position; - fieldLength = -1; - } - if (lineStart === bufLength) buffer = void 0; - else if (lineStart !== 0) { - buffer = buffer.subarray(lineStart); - position -= lineStart; - } - }; +function isMessagesPlaceholder(x) { + return x.constructor.lc_name() === "MessagesPlaceholder"; } /** -* Parses line buffers into EventSourceMessages. -* @param onId A function that will be called on each `id` field. -* @param onRetry A function that will be called on each `retry` field. -* @param onMessage A function that will be called on each message. -* @returns A function that should be called for each incoming line buffer. +* Class that represents a chat prompt. It extends the +* BaseChatPromptTemplate and uses an array of BaseMessagePromptTemplate +* instances to format a series of messages for a conversation. +* @example +* ```typescript +* const message = SystemMessagePromptTemplate.fromTemplate("{text}"); +* const chatPrompt = ChatPromptTemplate.fromMessages([ +* ["ai", "You are a helpful assistant."], +* message, +* ]); +* const formattedChatPrompt = await chatPrompt.invoke({ +* text: "Hello world!", +* }); +* ``` */ -function getMessages(onMessage, onId, onRetry) { - let message = newMessage(); - const decoder = new TextDecoder(); - return function onLine(line, fieldLength, flush) { - if (flush) { - if (!isEmpty(message)) { - onMessage?.(message); - message = newMessage(); +var ChatPromptTemplate = class ChatPromptTemplate extends BaseChatPromptTemplate { + static lc_name() { + return "ChatPromptTemplate"; + } + get lc_aliases() { + return { promptMessages: "messages" }; + } + promptMessages; + validateTemplate = true; + templateFormat = "f-string"; + constructor(input) { + super(input); + if (input.templateFormat === "mustache" && input.validateTemplate === void 0) this.validateTemplate = false; + Object.assign(this, input); + if (this.validateTemplate) { + const inputVariablesMessages = /* @__PURE__ */ new Set(); + for (const promptMessage of this.promptMessages) { + if (promptMessage instanceof BaseMessage) continue; + for (const inputVariable of promptMessage.inputVariables) inputVariablesMessages.add(inputVariable); } - return; + const totalInputVariables = this.inputVariables; + const inputVariablesInstance = new Set(this.partialVariables ? totalInputVariables.concat(Object.keys(this.partialVariables)) : totalInputVariables); + const difference = new Set([...inputVariablesInstance].filter((x) => !inputVariablesMessages.has(x))); + if (difference.size > 0) throw new Error(`Input variables \`${[...difference]}\` are not used in any of the prompt messages.`); + const otherDifference = new Set([...inputVariablesMessages].filter((x) => !inputVariablesInstance.has(x))); + if (otherDifference.size > 0) throw new Error(`Input variables \`${[...otherDifference]}\` are used in prompt messages but not in the prompt template.`); } - if (line.length === 0) { - onMessage?.(message); - message = newMessage(); - } else if (fieldLength > 0) { - const field = decoder.decode(line.subarray(0, fieldLength)); - const valueOffset = fieldLength + (line[fieldLength + 1] === ControlChars.Space ? 2 : 1); - const value = decoder.decode(line.subarray(valueOffset)); - switch (field) { - case "data": - message.data = message.data ? message.data + "\n" + value : value; - break; - case "event": - message.event = value; - break; - case "id": - onId?.(message.id = value); - break; - case "retry": { - const retry = parseInt(value, 10); - if (!Number.isNaN(retry)) onRetry?.(message.retry = retry); - break; + } + _getPromptType() { + return "chat"; + } + async _parseImagePrompts(message, inputValues) { + if (typeof message.content === "string") return message; + const formattedMessageContent = await Promise.all(message.content.map(async (item) => { + if (item.type !== "image_url") return item; + let imageUrl = ""; + if (typeof item.image_url === "string") imageUrl = item.image_url; + else if (typeof item.image_url === "object" && item.image_url !== null && "url" in item.image_url && typeof item.image_url.url === "string") imageUrl = item.image_url.url; + const promptTemplatePlaceholder = PromptTemplate.fromTemplate(imageUrl, { templateFormat: this.templateFormat }); + const formattedUrl = await promptTemplatePlaceholder.format(inputValues); + if (typeof item.image_url === "object" && item.image_url !== null && "url" in item.image_url) item.image_url.url = formattedUrl; + else item.image_url = formattedUrl; + return item; + })); + message.content = formattedMessageContent; + return message; + } + async formatMessages(values) { + const allValues = await this.mergePartialAndUserVariables(values); + let resultMessages = []; + for (const promptMessage of this.promptMessages) if (promptMessage instanceof BaseMessage) resultMessages.push(await this._parseImagePrompts(promptMessage, allValues)); + else { + let inputValues; + if (this.templateFormat === "mustache") inputValues = { ...allValues }; + else inputValues = promptMessage.inputVariables.reduce((acc, inputVariable) => { + if (!(inputVariable in allValues) && !(isMessagesPlaceholder(promptMessage) && promptMessage.optional)) { + const error = addLangChainErrorFields(/* @__PURE__ */ new Error(`Missing value for input variable \`${inputVariable.toString()}\``), "INVALID_PROMPT_INPUT"); + throw error; } + acc[inputVariable] = allValues[inputVariable]; + return acc; + }, {}); + const message = await promptMessage.formatMessages(inputValues); + resultMessages = resultMessages.concat(message); + } + return resultMessages; + } + async partial(values) { + const newInputVariables = this.inputVariables.filter((iv) => !(iv in values)); + const newPartialVariables = { + ...this.partialVariables ?? {}, + ...values + }; + const promptDict = { + ...this, + inputVariables: newInputVariables, + partialVariables: newPartialVariables + }; + return new ChatPromptTemplate(promptDict); + } + static fromTemplate(template, options) { + const prompt = PromptTemplate.fromTemplate(template, options); + const humanTemplate = new HumanMessagePromptTemplate({ prompt }); + return this.fromMessages([humanTemplate]); + } + /** + * Create a chat model-specific prompt from individual chat messages + * or message-like tuples. + * @param promptMessages Messages to be passed to the chat model + * @returns A new ChatPromptTemplate + */ + static fromMessages(promptMessages, extra) { + const flattenedMessages = promptMessages.reduce((acc, promptMessage) => acc.concat(promptMessage instanceof ChatPromptTemplate ? promptMessage.promptMessages : [_coerceMessagePromptTemplateLike(promptMessage, extra)]), []); + const flattenedPartialVariables = promptMessages.reduce((acc, promptMessage) => promptMessage instanceof ChatPromptTemplate ? Object.assign(acc, promptMessage.partialVariables) : acc, Object.create(null)); + const inputVariables = /* @__PURE__ */ new Set(); + for (const promptMessage of flattenedMessages) { + if (promptMessage instanceof BaseMessage) continue; + for (const inputVariable of promptMessage.inputVariables) { + if (inputVariable in flattenedPartialVariables) continue; + inputVariables.add(inputVariable); } } - }; -} -function event_source_parse_concat(a, b) { - const res = new Uint8Array(a.length + b.length); - res.set(a); - res.set(b, a.length); - return res; -} -function newMessage() { - return { - data: "", - event: "", - id: "", - retry: void 0 - }; -} -function convertEventStreamToIterableReadableDataStream(stream, onMetadataEvent) { - const dataStream = new ReadableStream({ async start(controller) { - const enqueueLine = getMessages((msg) => { - if (msg.event === "error") throw new Error(msg.data ?? "Unspecified event streaming error."); - else if (msg.event === "metadata") onMetadataEvent?.(msg); - else if (msg.data) controller.enqueue(msg.data); + return new this({ + ...extra, + inputVariables: [...inputVariables], + promptMessages: flattenedMessages, + partialVariables: flattenedPartialVariables, + templateFormat: extra?.templateFormat }); - const onLine = (line, fieldLength, flush) => { - enqueueLine(line, fieldLength, flush); - if (flush) controller.close(); - }; - await getBytes(stream, getLines(onLine)); - } }); - return IterableReadableStream.fromReadableStream(dataStream); -} -function isEmpty(message) { - return message.data === "" && message.event === "" && message.id === "" && message.retry === void 0; -} + } +}; //#endregion -//# sourceMappingURL=event_source_parse.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/bytes.js +//# sourceMappingURL=chat.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/few_shot.js -//#region src/output_parsers/bytes.ts + + + +//#region src/prompts/few_shot.ts /** -* OutputParser that parses LLMResult into the top likely string and -* encodes it into bytes. +* Prompt template that contains few-shot examples. +* @augments BasePromptTemplate +* @augments FewShotPromptTemplateInput +* @example +* ```typescript +* const examplePrompt = PromptTemplate.fromTemplate( +* "Input: {input}\nOutput: {output}", +* ); +* +* const exampleSelector = await SemanticSimilarityExampleSelector.fromExamples( +* [ +* { input: "happy", output: "sad" }, +* { input: "tall", output: "short" }, +* { input: "energetic", output: "lethargic" }, +* { input: "sunny", output: "gloomy" }, +* { input: "windy", output: "calm" }, +* ], +* new OpenAIEmbeddings(), +* HNSWLib, +* { k: 1 }, +* ); +* +* const dynamicPrompt = new FewShotPromptTemplate({ +* exampleSelector, +* examplePrompt, +* prefix: "Give the antonym of every input", +* suffix: "Input: {adjective}\nOutput:", +* inputVariables: ["adjective"], +* }); +* +* // Format the dynamic prompt with the input 'rainy' +* console.log(await dynamicPrompt.format({ adjective: "rainy" })); +* +* ``` */ -var BytesOutputParser = class extends BaseTransformOutputParser { +var FewShotPromptTemplate = class FewShotPromptTemplate extends BaseStringPromptTemplate { + lc_serializable = false; + examples; + exampleSelector; + examplePrompt; + suffix = ""; + exampleSeparator = "\n\n"; + prefix = ""; + templateFormat = "f-string"; + validateTemplate = true; + constructor(input) { + super(input); + Object.assign(this, input); + if (this.examples !== void 0 && this.exampleSelector !== void 0) throw new Error("Only one of 'examples' and 'example_selector' should be provided"); + if (this.examples === void 0 && this.exampleSelector === void 0) throw new Error("One of 'examples' and 'example_selector' should be provided"); + if (this.validateTemplate) { + let totalInputVariables = this.inputVariables; + if (this.partialVariables) totalInputVariables = totalInputVariables.concat(Object.keys(this.partialVariables)); + checkValidTemplate(this.prefix + this.suffix, this.templateFormat, totalInputVariables); + } + } + _getPromptType() { + return "few_shot"; + } static lc_name() { - return "BytesOutputParser"; + return "FewShotPromptTemplate"; } - lc_namespace = [ - "langchain_core", - "output_parsers", - "bytes" - ]; + async getExamples(inputVariables) { + if (this.examples !== void 0) return this.examples; + if (this.exampleSelector !== void 0) return this.exampleSelector.selectExamples(inputVariables); + throw new Error("One of 'examples' and 'example_selector' should be provided"); + } + async partial(values) { + const newInputVariables = this.inputVariables.filter((iv) => !(iv in values)); + const newPartialVariables = { + ...this.partialVariables ?? {}, + ...values + }; + const promptDict = { + ...this, + inputVariables: newInputVariables, + partialVariables: newPartialVariables + }; + return new FewShotPromptTemplate(promptDict); + } + /** + * Formats the prompt with the given values. + * @param values The values to format the prompt with. + * @returns A promise that resolves to a string representing the formatted prompt. + */ + async format(values) { + const allValues = await this.mergePartialAndUserVariables(values); + const examples = await this.getExamples(allValues); + const exampleStrings = await Promise.all(examples.map((example) => this.examplePrompt.format(example))); + const template = [ + this.prefix, + ...exampleStrings, + this.suffix + ].join(this.exampleSeparator); + return renderTemplate(template, this.templateFormat, allValues); + } + serialize() { + if (this.exampleSelector || !this.examples) throw new Error("Serializing an example selector is not currently supported"); + if (this.outputParser !== void 0) throw new Error("Serializing an output parser is not currently supported"); + return { + _type: this._getPromptType(), + input_variables: this.inputVariables, + example_prompt: this.examplePrompt.serialize(), + example_separator: this.exampleSeparator, + suffix: this.suffix, + prefix: this.prefix, + template_format: this.templateFormat, + examples: this.examples + }; + } + static async deserialize(data) { + const { example_prompt } = data; + if (!example_prompt) throw new Error("Missing example prompt"); + const examplePrompt = await PromptTemplate.deserialize(example_prompt); + let examples; + if (Array.isArray(data.examples)) examples = data.examples; + else throw new Error("Invalid examples format. Only list or string are supported."); + return new FewShotPromptTemplate({ + inputVariables: data.input_variables, + examplePrompt, + examples, + exampleSeparator: data.example_separator, + prefix: data.prefix, + suffix: data.suffix, + templateFormat: data.template_format + }); + } +}; +/** +* Chat prompt template that contains few-shot examples. +* @augments BasePromptTemplateInput +* @augments FewShotChatMessagePromptTemplateInput +*/ +var FewShotChatMessagePromptTemplate = class FewShotChatMessagePromptTemplate extends BaseChatPromptTemplate { lc_serializable = true; - textEncoder = new TextEncoder(); - parse(text) { - return Promise.resolve(this.textEncoder.encode(text)); + examples; + exampleSelector; + examplePrompt; + suffix = ""; + exampleSeparator = "\n\n"; + prefix = ""; + templateFormat = "f-string"; + validateTemplate = true; + _getPromptType() { + return "few_shot_chat"; } - getFormatInstructions() { - return ""; + static lc_name() { + return "FewShotChatMessagePromptTemplate"; + } + constructor(fields) { + super(fields); + this.examples = fields.examples; + this.examplePrompt = fields.examplePrompt; + this.exampleSeparator = fields.exampleSeparator ?? "\n\n"; + this.exampleSelector = fields.exampleSelector; + this.prefix = fields.prefix ?? ""; + this.suffix = fields.suffix ?? ""; + this.templateFormat = fields.templateFormat ?? "f-string"; + this.validateTemplate = fields.validateTemplate ?? true; + if (this.examples !== void 0 && this.exampleSelector !== void 0) throw new Error("Only one of 'examples' and 'example_selector' should be provided"); + if (this.examples === void 0 && this.exampleSelector === void 0) throw new Error("One of 'examples' and 'example_selector' should be provided"); + if (this.validateTemplate) { + let totalInputVariables = this.inputVariables; + if (this.partialVariables) totalInputVariables = totalInputVariables.concat(Object.keys(this.partialVariables)); + checkValidTemplate(this.prefix + this.suffix, this.templateFormat, totalInputVariables); + } + } + async getExamples(inputVariables) { + if (this.examples !== void 0) return this.examples; + if (this.exampleSelector !== void 0) return this.exampleSelector.selectExamples(inputVariables); + throw new Error("One of 'examples' and 'example_selector' should be provided"); + } + /** + * Formats the list of values and returns a list of formatted messages. + * @param values The values to format the prompt with. + * @returns A promise that resolves to a string representing the formatted prompt. + */ + async formatMessages(values) { + const allValues = await this.mergePartialAndUserVariables(values); + let examples = await this.getExamples(allValues); + examples = examples.map((example) => { + const result = {}; + this.examplePrompt.inputVariables.forEach((inputVariable) => { + result[inputVariable] = example[inputVariable]; + }); + return result; + }); + const messages = []; + for (const example of examples) { + const exampleMessages = await this.examplePrompt.formatMessages(example); + messages.push(...exampleMessages); + } + return messages; + } + /** + * Formats the prompt with the given values. + * @param values The values to format the prompt with. + * @returns A promise that resolves to a string representing the formatted prompt. + */ + async format(values) { + const allValues = await this.mergePartialAndUserVariables(values); + const examples = await this.getExamples(allValues); + const exampleMessages = await Promise.all(examples.map((example) => this.examplePrompt.formatMessages(example))); + const exampleStrings = exampleMessages.flat().map((message) => message.content); + const template = [ + this.prefix, + ...exampleStrings, + this.suffix + ].join(this.exampleSeparator); + return renderTemplate(template, this.templateFormat, allValues); + } + /** + * Partially formats the prompt with the given values. + * @param values The values to partially format the prompt with. + * @returns A promise that resolves to an instance of `FewShotChatMessagePromptTemplate` with the given values partially formatted. + */ + async partial(values) { + const newInputVariables = this.inputVariables.filter((variable) => !(variable in values)); + const newPartialVariables = { + ...this.partialVariables ?? {}, + ...values + }; + const promptDict = { + ...this, + inputVariables: newInputVariables, + partialVariables: newPartialVariables + }; + return new FewShotChatMessagePromptTemplate(promptDict); } }; //#endregion -//# sourceMappingURL=bytes.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/list.js +//# sourceMappingURL=few_shot.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/pipeline.js -//#region src/output_parsers/list.ts -/** -* Class to parse the output of an LLM call to a list. -* @augments BaseOutputParser -*/ -var ListOutputParser = class extends BaseTransformOutputParser { - re; - async *_transform(inputGenerator) { - let buffer = ""; - for await (const input of inputGenerator) { - if (typeof input === "string") buffer += input; - else buffer += input.content; - if (!this.re) { - const parts = await this.parse(buffer); - if (parts.length > 1) { - for (const part of parts.slice(0, -1)) yield [part]; - buffer = parts[parts.length - 1]; - } - } else { - const matches = [...buffer.matchAll(this.re)]; - if (matches.length > 1) { - let doneIdx = 0; - for (const match of matches.slice(0, -1)) { - yield [match[1]]; - doneIdx += (match.index ?? 0) + match[0].length; - } - buffer = buffer.slice(doneIdx); - } - } - } - for (const part of await this.parse(buffer)) yield [part]; - } -}; +//#region src/prompts/pipeline.ts /** -* Class to parse the output of an LLM call as a comma-separated list. -* @augments ListOutputParser +* Class that handles a sequence of prompts, each of which may require +* different input variables. Includes methods for formatting these +* prompts, extracting required input values, and handling partial +* prompts. +* @example +* ```typescript +* const composedPrompt = new PipelinePromptTemplate({ +* pipelinePrompts: [ +* { +* name: "introduction", +* prompt: PromptTemplate.fromTemplate(`You are impersonating {person}.`), +* }, +* { +* name: "example", +* prompt: PromptTemplate.fromTemplate( +* `Here's an example of an interaction: +* Q: {example_q} +* A: {example_a}`, +* ), +* }, +* { +* name: "start", +* prompt: PromptTemplate.fromTemplate( +* `Now, do this for real! +* Q: {input} +* A:`, +* ), +* }, +* ], +* finalPrompt: PromptTemplate.fromTemplate( +* `{introduction} +* {example} +* {start}`, +* ), +* }); +* +* const formattedPrompt = await composedPrompt.format({ +* person: "Elon Musk", +* example_q: `What's your favorite car?`, +* example_a: "Tesla", +* input: `What's your favorite social media site?`, +* }); +* ``` */ -var CommaSeparatedListOutputParser = class extends ListOutputParser { +var PipelinePromptTemplate = class PipelinePromptTemplate extends BasePromptTemplate { static lc_name() { - return "CommaSeparatedListOutputParser"; + return "PipelinePromptTemplate"; } - lc_namespace = [ - "langchain_core", - "output_parsers", - "list" - ]; - lc_serializable = true; - /** - * Parses the given text into an array of strings, using a comma as the - * separator. If the parsing fails, throws an OutputParserException. - * @param text The text to parse. - * @returns An array of strings obtained by splitting the input text at each comma. - */ - async parse(text) { - try { - return text.trim().split(",").map((s) => s.trim()); - } catch { - throw new OutputParserException(`Could not parse output: ${text}`, text); - } + pipelinePrompts; + finalPrompt; + constructor(input) { + super({ + ...input, + inputVariables: [] + }); + this.pipelinePrompts = input.pipelinePrompts; + this.finalPrompt = input.finalPrompt; + this.inputVariables = this.computeInputValues(); } /** - * Provides instructions on the expected format of the response for the - * CommaSeparatedListOutputParser. - * @returns A string containing instructions on the expected format of the response. + * Computes the input values required by the pipeline prompts. + * @returns Array of input values required by the pipeline prompts. */ - getFormatInstructions() { - return `Your response should be a list of comma separated values, eg: \`foo, bar, baz\``; + computeInputValues() { + const intermediateValues = this.pipelinePrompts.map((pipelinePrompt) => pipelinePrompt.name); + const inputValues = this.pipelinePrompts.map((pipelinePrompt) => pipelinePrompt.prompt.inputVariables.filter((inputValue) => !intermediateValues.includes(inputValue))).flat(); + return [...new Set(inputValues)]; } -}; -/** -* Class to parse the output of an LLM call to a list with a specific length and separator. -* @augments ListOutputParser -*/ -var CustomListOutputParser = class extends ListOutputParser { - lc_namespace = [ - "langchain_core", - "output_parsers", - "list" - ]; - length; - separator; - constructor({ length, separator }) { - super(...arguments); - this.length = length; - this.separator = separator || ","; + static extractRequiredInputValues(allValues, requiredValueNames) { + return requiredValueNames.reduce((requiredValues, valueName) => { + requiredValues[valueName] = allValues[valueName]; + return requiredValues; + }, {}); } /** - * Parses the given text into an array of strings, using the specified - * separator. If the parsing fails or the number of items in the list - * doesn't match the expected length, throws an OutputParserException. - * @param text The text to parse. - * @returns An array of strings obtained by splitting the input text at each occurrence of the specified separator. + * Formats the pipeline prompts based on the provided input values. + * @param values Input values to format the pipeline prompts. + * @returns Promise that resolves with the formatted input values. */ - async parse(text) { - try { - const items = text.trim().split(this.separator).map((s) => s.trim()); - if (this.length !== void 0 && items.length !== this.length) throw new OutputParserException(`Incorrect number of items. Expected ${this.length}, got ${items.length}.`); - return items; - } catch (e) { - if (Object.getPrototypeOf(e) === OutputParserException.prototype) throw e; - throw new OutputParserException(`Could not parse output: ${text}`); + async formatPipelinePrompts(values) { + const allValues = await this.mergePartialAndUserVariables(values); + for (const { name: pipelinePromptName, prompt: pipelinePrompt } of this.pipelinePrompts) { + const pipelinePromptInputValues = PipelinePromptTemplate.extractRequiredInputValues(allValues, pipelinePrompt.inputVariables); + if (pipelinePrompt instanceof ChatPromptTemplate) allValues[pipelinePromptName] = await pipelinePrompt.formatMessages(pipelinePromptInputValues); + else allValues[pipelinePromptName] = await pipelinePrompt.format(pipelinePromptInputValues); } + return PipelinePromptTemplate.extractRequiredInputValues(allValues, this.finalPrompt.inputVariables); } /** - * Provides instructions on the expected format of the response for the - * CustomListOutputParser, including the number of items and the - * separator. - * @returns A string containing instructions on the expected format of the response. + * Formats the final prompt value based on the provided input values. + * @param values Input values to format the final prompt value. + * @returns Promise that resolves with the formatted final prompt value. */ - getFormatInstructions() { - return `Your response should be a list of ${this.length === void 0 ? "" : `${this.length} `}items separated by "${this.separator}" (eg: \`foo${this.separator} bar${this.separator} baz\`)`; + async formatPromptValue(values) { + return this.finalPrompt.formatPromptValue(await this.formatPipelinePrompts(values)); } -}; -var NumberedListOutputParser = class extends ListOutputParser { - static lc_name() { - return "NumberedListOutputParser"; + async format(values) { + return this.finalPrompt.format(await this.formatPipelinePrompts(values)); } - lc_namespace = [ - "langchain_core", - "output_parsers", - "list" - ]; - lc_serializable = true; - getFormatInstructions() { - return `Your response should be a numbered list with each item on a new line. For example: \n\n1. foo\n\n2. bar\n\n3. baz`; + /** + * Handles partial prompts, which are prompts that have been partially + * filled with input values. + * @param values Partial input values. + * @returns Promise that resolves with a new PipelinePromptTemplate instance with updated input variables. + */ + async partial(values) { + const promptDict = { ...this }; + promptDict.inputVariables = this.inputVariables.filter((iv) => !(iv in values)); + promptDict.partialVariables = { + ...this.partialVariables ?? {}, + ...values + }; + return new PipelinePromptTemplate(promptDict); } - re = /\d+\.\s([^\n]+)/g; - async parse(text) { - return [...text.matchAll(this.re) ?? []].map((m) => m[1]); + serialize() { + throw new Error("Not implemented."); } -}; -var MarkdownListOutputParser = class extends ListOutputParser { - static lc_name() { - return "NumberedListOutputParser"; + _getPromptType() { + return "pipeline"; } +}; + +//#endregion + +//# sourceMappingURL=pipeline.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/structured.js + + + +//#region src/prompts/structured.ts +function isWithStructuredOutput(x) { + return typeof x === "object" && x != null && "withStructuredOutput" in x && typeof x.withStructuredOutput === "function"; +} +function isRunnableBinding(x) { + return typeof x === "object" && x != null && "lc_id" in x && Array.isArray(x.lc_id) && x.lc_id.join("/") === "langchain_core/runnables/RunnableBinding"; +} +var StructuredPrompt = class StructuredPrompt extends ChatPromptTemplate { + schema; + method; lc_namespace = [ "langchain_core", - "output_parsers", - "list" + "prompts", + "structured" ]; - lc_serializable = true; - getFormatInstructions() { - return `Your response should be a numbered list with each item on a new line. For example: \n\n1. foo\n\n2. bar\n\n3. baz`; + get lc_aliases() { + return { + ...super.lc_aliases, + schema: "schema_" + }; } - re = /^\s*[-*]\s([^\n]+)$/gm; - async parse(text) { - return [...text.matchAll(this.re) ?? []].map((m) => m[1]); + constructor(input) { + super(input); + this.schema = input.schema; + this.method = input.method; + } + pipe(coerceable) { + if (isWithStructuredOutput(coerceable)) return super.pipe(coerceable.withStructuredOutput(this.schema)); + if (isRunnableBinding(coerceable) && isWithStructuredOutput(coerceable.bound)) return super.pipe(new RunnableBinding({ + bound: coerceable.bound.withStructuredOutput(this.schema, ...this.method ? [{ method: this.method }] : []), + kwargs: coerceable.kwargs ?? {}, + config: coerceable.config, + configFactories: coerceable.configFactories + })); + throw new Error(`Structured prompts need to be piped to a language model that supports the "withStructuredOutput()" method.`); + } + static fromMessagesAndSchema(promptMessages, schema, method) { + return StructuredPrompt.fromMessages(promptMessages, { + schema, + method + }); } }; //#endregion -//# sourceMappingURL=list.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/string.js +//# sourceMappingURL=structured.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/prompts/index.js -//#region src/output_parsers/string.ts + + + + + + + + + + +//#region src/prompts/index.ts +var prompts_exports = {}; +__export(prompts_exports, { + AIMessagePromptTemplate: () => AIMessagePromptTemplate, + BaseChatPromptTemplate: () => BaseChatPromptTemplate, + BaseMessagePromptTemplate: () => BaseMessagePromptTemplate, + BaseMessageStringPromptTemplate: () => BaseMessageStringPromptTemplate, + BasePromptTemplate: () => BasePromptTemplate, + BaseStringPromptTemplate: () => BaseStringPromptTemplate, + ChatMessagePromptTemplate: () => ChatMessagePromptTemplate, + ChatPromptTemplate: () => ChatPromptTemplate, + DEFAULT_FORMATTER_MAPPING: () => DEFAULT_FORMATTER_MAPPING, + DEFAULT_PARSER_MAPPING: () => DEFAULT_PARSER_MAPPING, + DictPromptTemplate: () => DictPromptTemplate, + FewShotChatMessagePromptTemplate: () => FewShotChatMessagePromptTemplate, + FewShotPromptTemplate: () => FewShotPromptTemplate, + HumanMessagePromptTemplate: () => HumanMessagePromptTemplate, + ImagePromptTemplate: () => ImagePromptTemplate, + MessagesPlaceholder: () => MessagesPlaceholder, + PipelinePromptTemplate: () => PipelinePromptTemplate, + PromptTemplate: () => PromptTemplate, + StructuredPrompt: () => StructuredPrompt, + SystemMessagePromptTemplate: () => SystemMessagePromptTemplate, + checkValidTemplate: () => checkValidTemplate, + interpolateFString: () => interpolateFString, + interpolateMustache: () => interpolateMustache, + parseFString: () => parseFString, + parseMustache: () => parseMustache, + parseTemplate: () => template_parseTemplate, + renderTemplate: () => renderTemplate +}); + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/retrievers/document_compressors/index.js + + +//#region src/retrievers/document_compressors/index.ts +var document_compressors_exports = {}; +__export(document_compressors_exports, { BaseDocumentCompressor: () => BaseDocumentCompressor }); /** -* OutputParser that parses LLMResult into the top likely string. -* @example -* ```typescript -* const promptTemplate = PromptTemplate.fromTemplate( -* "Tell me a joke about {topic}", -* ); -* -* const chain = RunnableSequence.from([ -* promptTemplate, -* new ChatOpenAI({ model: "gpt-4o-mini" }), -* new StringOutputParser(), -* ]); -* -* const result = await chain.invoke({ topic: "bears" }); -* console.log("What do you call a bear with no teeth? A gummy bear!"); -* ``` +* Base Document Compression class. All compressors should extend this class. */ -var StringOutputParser = class extends BaseTransformOutputParser { - static lc_name() { - return "StrOutputParser"; +var BaseDocumentCompressor = class { + static isBaseDocumentCompressor(x) { + return x?.compressDocuments !== void 0; } - lc_namespace = [ - "langchain_core", - "output_parsers", - "string" - ]; - lc_serializable = true; - /** - * Parses a string output from an LLM call. This method is meant to be - * implemented by subclasses to define how a string output from an LLM - * should be parsed. - * @param text The string output from an LLM call. - * @param callbacks Optional callbacks. - * @returns A promise of the parsed output. - */ - parse(text) { - return Promise.resolve(text); +}; + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/ir.js +//#region src/structured_query/ir.ts +const Operators = { + and: "and", + or: "or", + not: "not" +}; +const Comparators = { + eq: "eq", + ne: "ne", + lt: "lt", + gt: "gt", + lte: "lte", + gte: "gte" +}; +/** +* Abstract class for visiting expressions. Subclasses must implement +* visitOperation, visitComparison, and visitStructuredQuery methods. +*/ +var Visitor = class {}; +/** +* Abstract class representing an expression. Subclasses must implement +* the exprName property and the accept method. +*/ +var Expression = class { + accept(visitor) { + if (this.exprName === "Operation") return visitor.visitOperation(this); + else if (this.exprName === "Comparison") return visitor.visitComparison(this); + else if (this.exprName === "StructuredQuery") return visitor.visitStructuredQuery(this); + else throw new Error("Unknown Expression type"); } - getFormatInstructions() { - return ""; +}; +/** +* Abstract class representing a filter directive. It extends the +* Expression class. +*/ +var FilterDirective = class extends Expression {}; +/** +* Class representing a comparison filter directive. It extends the +* FilterDirective class. +*/ +var Comparison = class extends FilterDirective { + exprName = "Comparison"; + constructor(comparator, attribute, value) { + super(); + this.comparator = comparator; + this.attribute = attribute; + this.value = value; } - _textContentToString(content) { - return content.text; +}; +/** +* Class representing an operation filter directive. It extends the +* FilterDirective class. +*/ +var Operation = class extends FilterDirective { + exprName = "Operation"; + constructor(operator, args) { + super(); + this.operator = operator; + this.args = args; } - _imageUrlContentToString(_content) { - throw new Error(`Cannot coerce a multimodal "image_url" message part into a string.`); +}; +/** +* Class representing a structured query expression. It extends the +* Expression class. +*/ +var StructuredQuery = class extends Expression { + exprName = "StructuredQuery"; + constructor(query, filter) { + super(); + this.query = query; + this.filter = filter; } - _messageContentToString(content) { - switch (content.type) { - case "text": - case "text_delta": - if ("text" in content) return this._textContentToString(content); - break; - case "image_url": - if ("image_url" in content) return this._imageUrlContentToString(content); - break; - default: throw new Error(`Cannot coerce "${content.type}" message part into a string.`); - } - throw new Error(`Invalid content type: ${content.type}`); +}; + +//#endregion + +//# sourceMappingURL=ir.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/utils.js +//#region src/structured_query/utils.ts +/** +* Checks if the provided argument is an object and not an array. +*/ +function isObject(obj) { + return obj && typeof obj === "object" && !Array.isArray(obj); +} +/** +* Checks if a provided filter is empty. The filter can be a function, an +* object, a string, or undefined. +*/ +function isFilterEmpty(filter) { + if (!filter) return true; + if (typeof filter === "string" && filter.length > 0) return false; + if (typeof filter === "function") return false; + return isObject(filter) && Object.keys(filter).length === 0; +} +/** +* Checks if the provided value is an integer. +*/ +function isInt(value) { + if (typeof value === "number") return value % 1 === 0; + else if (typeof value === "string") { + const numberValue = parseInt(value, 10); + return !Number.isNaN(numberValue) && numberValue % 1 === 0 && numberValue.toString() === value; } - _baseMessageContentToString(content) { - return content.reduce((acc, item) => acc + this._messageContentToString(item), ""); + return false; +} +/** +* Checks if the provided value is a floating-point number. +*/ +function isFloat(value) { + if (typeof value === "number") return value % 1 !== 0; + else if (typeof value === "string") { + const numberValue = parseFloat(value); + return !Number.isNaN(numberValue) && numberValue % 1 !== 0 && numberValue.toString() === value; } -}; + return false; +} +/** +* Checks if the provided value is a string that cannot be parsed into a +* number. +*/ +function isString(value) { + return typeof value === "string" && (Number.isNaN(parseFloat(value)) || parseFloat(value).toString() !== value); +} +/** +* Checks if the provided value is a boolean. +*/ +function isBoolean(value) { + return typeof value === "boolean"; +} +/** +* Casts a value that might be string or number to actual string or number. +* Since LLM might return back an integer/float as a string, we need to cast +* it back to a number, as many vector databases can't handle number as string +* values as a comparator. +*/ +function castValue(input) { + let value; + if (isString(input)) value = input; + else if (isInt(input)) value = parseInt(input, 10); + else if (isFloat(input)) value = parseFloat(input); + else if (isBoolean(input)) value = Boolean(input); + else throw new Error("Unsupported value type"); + return value; +} //#endregion -//# sourceMappingURL=string.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/structured.js - - +//# sourceMappingURL=utils.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/base.js -//#region src/output_parsers/structured.ts -var StructuredOutputParser = class extends BaseOutputParser { - static lc_name() { - return "StructuredOutputParser"; - } - lc_namespace = [ - "langchain", - "output_parsers", - "structured" - ]; - toJSON() { - return this.toJSONNotImplemented(); - } - constructor(schema) { - super(schema); - this.schema = schema; +//#region src/structured_query/base.ts +/** +* Abstract class that provides a blueprint for creating specific +* translator classes. Defines two abstract methods: formatFunction and +* mergeFilters. +*/ +var BaseTranslator = class extends Visitor {}; +/** +* Class that extends the BaseTranslator class and provides concrete +* implementations for the abstract methods. Also declares three types: +* VisitOperationOutput, VisitComparisonOutput, and +* VisitStructuredQueryOutput, which are used as the return types for the +* visitOperation, visitComparison, and visitStructuredQuery methods +* respectively. +*/ +var BasicTranslator = class extends BaseTranslator { + allowedOperators; + allowedComparators; + constructor(opts) { + super(); + this.allowedOperators = opts?.allowedOperators ?? [Operators.and, Operators.or]; + this.allowedComparators = opts?.allowedComparators ?? [ + Comparators.eq, + Comparators.ne, + Comparators.gt, + Comparators.gte, + Comparators.lt, + Comparators.lte + ]; } - /** - * Creates a new StructuredOutputParser from a Zod schema. - * @param schema The Zod schema which the output should match - * @returns A new instance of StructuredOutputParser. - */ - static fromZodSchema(schema) { - return new this(schema); + formatFunction(func) { + if (func in Comparators) { + if (this.allowedComparators.length > 0 && this.allowedComparators.indexOf(func) === -1) throw new Error(`Comparator ${func} not allowed. Allowed comparators: ${this.allowedComparators.join(", ")}`); + } else if (func in Operators) { + if (this.allowedOperators.length > 0 && this.allowedOperators.indexOf(func) === -1) throw new Error(`Operator ${func} not allowed. Allowed operators: ${this.allowedOperators.join(", ")}`); + } else throw new Error("Unknown comparator or operator"); + return `$${func}`; } /** - * Creates a new StructuredOutputParser from a set of names and - * descriptions. - * @param schemas An object where each key is a name and each value is a description - * @returns A new instance of StructuredOutputParser. + * Visits an operation and returns a result. + * @param operation The operation to visit. + * @returns The result of visiting the operation. */ - static fromNamesAndDescriptions(schemas) { - const zodSchema = objectType(Object.fromEntries(Object.entries(schemas).map(([name, description]) => [name, stringType().describe(description)]))); - return new this(zodSchema); + visitOperation(operation) { + const args = operation.args?.map((arg) => arg.accept(this)); + return { [this.formatFunction(operation.operator)]: args }; } /** - * Returns a markdown code snippet with a JSON object formatted according - * to the schema. - * @param options Optional. The options for formatting the instructions - * @returns A markdown code snippet with a JSON object formatted according to the schema. + * Visits a comparison and returns a result. + * @param comparison The comparison to visit. + * @returns The result of visiting the comparison. */ - getFormatInstructions() { - return `You must format your output as a JSON value that adheres to a given "JSON Schema" instance. - -"JSON Schema" is a declarative language that allows you to annotate and validate JSON documents. - -For example, the example "JSON Schema" instance {{"properties": {{"foo": {{"description": "a list of test words", "type": "array", "items": {{"type": "string"}}}}}}, "required": ["foo"]}} -would match an object with one required property, "foo". The "type" property specifies "foo" must be an "array", and the "description" property semantically describes it as "a list of test words". The items within "foo" must be strings. -Thus, the object {{"foo": ["bar", "baz"]}} is a well-formatted instance of this example "JSON Schema". The object {{"properties": {{"foo": ["bar", "baz"]}}}} is not well-formatted. - -Your output will be parsed and type-checked according to the provided schema instance, so make sure all fields in your output match the schema exactly and there are no trailing commas! - -Here is the JSON Schema instance your output must adhere to. Include the enclosing markdown codeblock: -\`\`\`json -${JSON.stringify(toJsonSchema(this.schema))} -\`\`\` -`; + visitComparison(comparison) { + return { [comparison.attribute]: { [this.formatFunction(comparison.comparator)]: castValue(comparison.value) } }; } /** - * Parses the given text according to the schema. - * @param text The text to parse - * @returns The parsed output. + * Visits a structured query and returns a result. + * @param query The structured query to visit. + * @returns The result of visiting the structured query. */ - async parse(text) { - try { - const trimmedText = text.trim(); - const json = trimmedText.match(/^```(?:json)?\s*([\s\S]*?)```/)?.[1] || trimmedText.match(/```json\s*([\s\S]*?)```/)?.[1] || trimmedText; - const escapedJson = json.replace(/"([^"\\]*(\\.[^"\\]*)*)"/g, (_match, capturedGroup) => { - const escapedInsideQuotes = capturedGroup.replace(/\n/g, "\\n"); - return `"${escapedInsideQuotes}"`; - }).replace(/\n/g, ""); - return await interopParseAsync(this.schema, JSON.parse(escapedJson)); - } catch (e) { - throw new OutputParserException(`Failed to parse. Text: "${text}". Error: ${e}`, text); - } - } -}; -/** -* A specific type of `StructuredOutputParser` that parses JSON data -* formatted as a markdown code snippet. -*/ -var JsonMarkdownStructuredOutputParser = class extends StructuredOutputParser { - static lc_name() { - return "JsonMarkdownStructuredOutputParser"; - } - getFormatInstructions(options) { - const interpolationDepth = options?.interpolationDepth ?? 1; - if (interpolationDepth < 1) throw new Error("f string interpolation depth must be at least 1"); - return `Return a markdown code snippet with a JSON object formatted to look like:\n\`\`\`json\n${this._schemaToInstruction(toJsonSchema(this.schema)).replaceAll("{", "{".repeat(interpolationDepth)).replaceAll("}", "}".repeat(interpolationDepth))}\n\`\`\``; + visitStructuredQuery(query) { + let nextArg = {}; + if (query.filter) nextArg = { filter: query.filter.accept(this) }; + return nextArg; } - _schemaToInstruction(schemaInput, indent = 2) { - const schema = schemaInput; - if ("type" in schema) { - let nullable = false; - let type; - if (Array.isArray(schema.type)) { - const nullIdx = schema.type.findIndex((type$1) => type$1 === "null"); - if (nullIdx !== -1) { - nullable = true; - schema.type.splice(nullIdx, 1); - } - type = schema.type.join(" | "); - } else type = schema.type; - if (schema.type === "object" && schema.properties) { - const description$1 = schema.description ? ` // ${schema.description}` : ""; - const properties = Object.entries(schema.properties).map(([key, value]) => { - const isOptional = schema.required?.includes(key) ? "" : " (optional)"; - return `${" ".repeat(indent)}"${key}": ${this._schemaToInstruction(value, indent + 2)}${isOptional}`; - }).join("\n"); - return `{\n${properties}\n${" ".repeat(indent - 2)}}${description$1}`; - } - if (schema.type === "array" && schema.items) { - const description$1 = schema.description ? ` // ${schema.description}` : ""; - return `array[\n${" ".repeat(indent)}${this._schemaToInstruction(schema.items, indent + 2)}\n${" ".repeat(indent - 2)}] ${description$1}`; - } - const isNullable = nullable ? " (nullable)" : ""; - const description = schema.description ? ` // ${schema.description}` : ""; - return `${type}${description}${isNullable}`; + mergeFilters(defaultFilter, generatedFilter, mergeType = "and", forceDefaultFilter = false) { + if (isFilterEmpty(defaultFilter) && isFilterEmpty(generatedFilter)) return void 0; + if (isFilterEmpty(defaultFilter) || mergeType === "replace") { + if (isFilterEmpty(generatedFilter)) return void 0; + return generatedFilter; } - if ("anyOf" in schema) return schema.anyOf.map((s) => this._schemaToInstruction(s, indent)).join(`\n${" ".repeat(indent - 2)}`); - throw new Error("unsupported schema type"); - } - static fromZodSchema(schema) { - return new this(schema); - } - static fromNamesAndDescriptions(schemas) { - const zodSchema = objectType(Object.fromEntries(Object.entries(schemas).map(([name, description]) => [name, stringType().describe(description)]))); - return new this(zodSchema); - } -}; -/** -* A type of `StructuredOutputParser` that handles asymmetric input and -* output schemas. -*/ -var AsymmetricStructuredOutputParser = class extends BaseOutputParser { - structuredInputParser; - constructor({ inputSchema }) { - super(...arguments); - this.structuredInputParser = new JsonMarkdownStructuredOutputParser(inputSchema); - } - async parse(text) { - let parsedInput; - try { - parsedInput = await this.structuredInputParser.parse(text); - } catch (e) { - throw new OutputParserException(`Failed to parse. Text: "${text}". Error: ${e}`, text); + if (isFilterEmpty(generatedFilter)) { + if (forceDefaultFilter) return defaultFilter; + if (mergeType === "and") return void 0; + return defaultFilter; } - return this.outputProcessor(parsedInput); - } - getFormatInstructions() { - return this.structuredInputParser.getFormatInstructions(); + if (mergeType === "and") return { $and: [defaultFilter, generatedFilter] }; + else if (mergeType === "or") return { $or: [defaultFilter, generatedFilter] }; + else throw new Error("Unknown merge type"); } }; //#endregion -//# sourceMappingURL=structured.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/sax-js/sax.js -//#region src/utils/sax-js/sax.ts -const initializeSax = function() { - const sax$1 = {}; - sax$1.parser = function(strict, opt) { - return new SAXParser(strict, opt); - }; - sax$1.SAXParser = SAXParser; - sax$1.SAXStream = SAXStream; - sax$1.createStream = createStream; - sax$1.MAX_BUFFER_LENGTH = 64 * 1024; - const buffers = [ - "comment", - "sgmlDecl", - "textNode", - "tagName", - "doctype", - "procInstName", - "procInstBody", - "entity", - "attribName", - "attribValue", - "cdata", - "script" - ]; - sax$1.EVENTS = [ - "text", - "processinginstruction", - "sgmldeclaration", - "doctype", - "comment", - "opentagstart", - "attribute", - "opentag", - "closetag", - "opencdata", - "cdata", - "closecdata", - "error", - "end", - "ready", - "script", - "opennamespace", - "closenamespace" +//# sourceMappingURL=base.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/functional.js + + + + +//#region src/structured_query/functional.ts +/** +* A class that extends `BaseTranslator` to translate structured queries +* into functional filters. +* @example +* ```typescript +* const functionalTranslator = new FunctionalTranslator(); +* const relevantDocuments = await functionalTranslator.getRelevantDocuments( +* "Which movies are rated higher than 8.5?", +* ); +* ``` +*/ +var FunctionalTranslator = class extends BaseTranslator { + allowedOperators = [Operators.and, Operators.or]; + allowedComparators = [ + Comparators.eq, + Comparators.ne, + Comparators.gt, + Comparators.gte, + Comparators.lt, + Comparators.lte ]; - function SAXParser(strict, opt) { - if (!(this instanceof SAXParser)) return new SAXParser(strict, opt); - var parser = this; - clearBuffers(parser); - parser.q = parser.c = ""; - parser.bufferCheckPosition = sax$1.MAX_BUFFER_LENGTH; - parser.opt = opt || {}; - parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags; - parser.looseCase = parser.opt.lowercase ? "toLowerCase" : "toUpperCase"; - parser.tags = []; - parser.closed = parser.closedRoot = parser.sawRoot = false; - parser.tag = parser.error = null; - parser.strict = !!strict; - parser.noscript = !!(strict || parser.opt.noscript); - parser.state = S.BEGIN; - parser.strictEntities = parser.opt.strictEntities; - parser.ENTITIES = parser.strictEntities ? Object.create(sax$1.XML_ENTITIES) : Object.create(sax$1.ENTITIES); - parser.attribList = []; - if (parser.opt.xmlns) parser.ns = Object.create(rootNS); - parser.trackPosition = parser.opt.position !== false; - if (parser.trackPosition) parser.position = parser.line = parser.column = 0; - emit(parser, "onready"); - } - if (!Object.create) Object.create = function(o) { - function F() {} - F.prototype = o; - var newf = new F(); - return newf; - }; - if (!Object.keys) Object.keys = function(o) { - var a = []; - for (var i in o) if (o.hasOwnProperty(i)) a.push(i); - return a; - }; - function checkBufferLength(parser) { - var maxAllowed = Math.max(sax$1.MAX_BUFFER_LENGTH, 10); - var maxActual = 0; - for (var i = 0, l = buffers.length; i < l; i++) { - var len = parser[buffers[i]].length; - if (len > maxAllowed) switch (buffers[i]) { - case "textNode": - closeText(parser); - break; - case "cdata": - emitNode(parser, "oncdata", parser.cdata); - parser.cdata = ""; - break; - case "script": - emitNode(parser, "onscript", parser.script); - parser.script = ""; - break; - default: error(parser, "Max buffer length exceeded: " + buffers[i]); - } - maxActual = Math.max(maxActual, len); - } - var m = sax$1.MAX_BUFFER_LENGTH - maxActual; - parser.bufferCheckPosition = m + parser.position; - } - function clearBuffers(parser) { - for (var i = 0, l = buffers.length; i < l; i++) parser[buffers[i]] = ""; - } - function flushBuffers(parser) { - closeText(parser); - if (parser.cdata !== "") { - emitNode(parser, "oncdata", parser.cdata); - parser.cdata = ""; - } - if (parser.script !== "") { - emitNode(parser, "onscript", parser.script); - parser.script = ""; - } + formatFunction() { + throw new Error("Not implemented"); } - SAXParser.prototype = { - end: function() { - end(this); - }, - write, - resume: function() { - this.error = null; - return this; - }, - close: function() { - return this.write(null); - }, - flush: function() { - flushBuffers(this); + /** + * Returns the allowed comparators for a given data type. + * @param input The input value to get the allowed comparators for. + * @returns An array of allowed comparators for the input data type. + */ + getAllowedComparatorsForType(inputType) { + switch (inputType) { + case "string": return [ + Comparators.eq, + Comparators.ne, + Comparators.gt, + Comparators.gte, + Comparators.lt, + Comparators.lte + ]; + case "number": return [ + Comparators.eq, + Comparators.ne, + Comparators.gt, + Comparators.gte, + Comparators.lt, + Comparators.lte + ]; + case "boolean": return [Comparators.eq, Comparators.ne]; + default: throw new Error(`Unsupported data type: ${inputType}`); } - }; - var Stream = ReadableStream; - if (!Stream) Stream = function() {}; - var streamWraps = sax$1.EVENTS.filter(function(ev) { - return ev !== "error" && ev !== "end"; - }); - function createStream(strict, opt) { - return new SAXStream(strict, opt); - } - function SAXStream(strict, opt) { - if (!(this instanceof SAXStream)) return new SAXStream(strict, opt); - Stream.apply(this); - this._parser = new SAXParser(strict, opt); - this.writable = true; - this.readable = true; - var me = this; - this._parser.onend = function() { - me.emit("end"); - }; - this._parser.onerror = function(er) { - me.emit("error", er); - me._parser.error = null; - }; - this._decoder = null; - streamWraps.forEach(function(ev) { - Object.defineProperty(me, "on" + ev, { - get: function() { - return me._parser["on" + ev]; - }, - set: function(h) { - if (!h) { - me.removeAllListeners(ev); - me._parser["on" + ev] = h; - return h; - } - me.on(ev, h); - }, - enumerable: true, - configurable: false - }); - }); } - SAXStream.prototype = Object.create(Stream.prototype, { constructor: { value: SAXStream } }); - SAXStream.prototype.write = function(data) { - this._parser.write(data.toString()); - this.emit("data", data); - return true; - }; - SAXStream.prototype.end = function(chunk) { - if (chunk && chunk.length) this.write(chunk); - this._parser.end(); - return true; - }; - SAXStream.prototype.on = function(ev, handler) { - var me = this; - if (!me._parser["on" + ev] && streamWraps.indexOf(ev) !== -1) me._parser["on" + ev] = function() { - var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments); - args.splice(0, 0, ev); - me.emit.apply(me, args); - }; - return Stream.prototype.on.call(me, ev, handler); - }; - var CDATA = "[CDATA["; - var DOCTYPE = "DOCTYPE"; - var XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace"; - var XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/"; - var rootNS = { - xml: XML_NAMESPACE, - xmlns: XMLNS_NAMESPACE - }; - var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/; - var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/; - var entityStart = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/; - var entityBody = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/; - function isWhitespace(c) { - return c === " " || c === "\n" || c === "\r" || c === " "; + /** + * Returns a function that performs a comparison based on the provided + * comparator. + * @param comparator The comparator to base the comparison function on. + * @returns A function that takes two arguments and returns a boolean based on the comparison. + */ + getComparatorFunction(comparator) { + switch (comparator) { + case Comparators.eq: return (a, b) => a === b; + case Comparators.ne: return (a, b) => a !== b; + case Comparators.gt: return (a, b) => a > b; + case Comparators.gte: return (a, b) => a >= b; + case Comparators.lt: return (a, b) => a < b; + case Comparators.lte: return (a, b) => a <= b; + default: throw new Error("Unknown comparator"); + } } - function isQuote(c) { - return c === "\"" || c === "'"; + /** + * Returns a function that performs an operation based on the provided + * operator. + * @param operator The operator to base the operation function on. + * @returns A function that takes two boolean arguments and returns a boolean based on the operation. + */ + getOperatorFunction(operator) { + switch (operator) { + case Operators.and: return (a, b) => a && b; + case Operators.or: return (a, b) => a || b; + default: throw new Error("Unknown operator"); + } } - function isAttribEnd(c) { - return c === ">" || isWhitespace(c); + /** + * Visits the operation part of a structured query and translates it into + * a functional filter. + * @param operation The operation part of a structured query. + * @returns A function that takes a `Document` as an argument and returns a boolean based on the operation. + */ + visitOperation(operation) { + const { operator, args } = operation; + if (this.allowedOperators.includes(operator)) { + const operatorFunction = this.getOperatorFunction(operator); + return (document) => { + if (!args) return true; + return args.reduce((acc, arg) => { + const result = arg.accept(this); + if (typeof result === "function") return operatorFunction(acc, result(document)); + else throw new Error("Filter is not a function"); + }, true); + }; + } else throw new Error("Operator not allowed"); } - function isMatch(regex, c) { - return regex.test(c); + /** + * Visits the comparison part of a structured query and translates it into + * a functional filter. + * @param comparison The comparison part of a structured query. + * @returns A function that takes a `Document` as an argument and returns a boolean based on the comparison. + */ + visitComparison(comparison) { + const { comparator, attribute, value } = comparison; + const undefinedTrue = [Comparators.ne]; + if (this.allowedComparators.includes(comparator)) { + if (!this.getAllowedComparatorsForType(typeof value).includes(comparator)) throw new Error(`'${comparator}' comparator not allowed to be used with ${typeof value}`); + const comparatorFunction = this.getComparatorFunction(comparator); + return (document) => { + const documentValue = document.metadata[attribute]; + if (documentValue === void 0) { + if (undefinedTrue.includes(comparator)) return true; + return false; + } + return comparatorFunction(documentValue, castValue(value)); + }; + } else throw new Error("Comparator not allowed"); } - function notMatch(regex, c) { - return !isMatch(regex, c); + /** + * Visits a structured query and translates it into a functional filter. + * @param query The structured query to translate. + * @returns An object containing a `filter` property, which is a function that takes a `Document` as an argument and returns a boolean based on the structured query. + */ + visitStructuredQuery(query) { + if (!query.filter) return {}; + const filterFunction = query.filter?.accept(this); + if (typeof filterFunction !== "function") throw new Error("Structured query filter is not a function"); + return { filter: filterFunction }; } - var S = 0; - sax$1.STATE = { - BEGIN: S++, - BEGIN_WHITESPACE: S++, - TEXT: S++, - TEXT_ENTITY: S++, - OPEN_WAKA: S++, - SGML_DECL: S++, - SGML_DECL_QUOTED: S++, - DOCTYPE: S++, - DOCTYPE_QUOTED: S++, - DOCTYPE_DTD: S++, - DOCTYPE_DTD_QUOTED: S++, - COMMENT_STARTING: S++, - COMMENT: S++, - COMMENT_ENDING: S++, - COMMENT_ENDED: S++, - CDATA: S++, - CDATA_ENDING: S++, - CDATA_ENDING_2: S++, - PROC_INST: S++, - PROC_INST_BODY: S++, - PROC_INST_ENDING: S++, - OPEN_TAG: S++, - OPEN_TAG_SLASH: S++, - ATTRIB: S++, - ATTRIB_NAME: S++, - ATTRIB_NAME_SAW_WHITE: S++, - ATTRIB_VALUE: S++, - ATTRIB_VALUE_QUOTED: S++, - ATTRIB_VALUE_CLOSED: S++, - ATTRIB_VALUE_UNQUOTED: S++, - ATTRIB_VALUE_ENTITY_Q: S++, - ATTRIB_VALUE_ENTITY_U: S++, - CLOSE_TAG: S++, - CLOSE_TAG_SAW_WHITE: S++, - SCRIPT: S++, - SCRIPT_ENDING: S++ - }; - sax$1.XML_ENTITIES = { - amp: "&", - gt: ">", - lt: "<", - quot: "\"", - apos: "'" - }; - sax$1.ENTITIES = { - amp: "&", - gt: ">", - lt: "<", - quot: "\"", - apos: "'", - AElig: 198, - Aacute: 193, - Acirc: 194, - Agrave: 192, - Aring: 197, - Atilde: 195, - Auml: 196, - Ccedil: 199, - ETH: 208, - Eacute: 201, - Ecirc: 202, - Egrave: 200, - Euml: 203, - Iacute: 205, - Icirc: 206, - Igrave: 204, - Iuml: 207, - Ntilde: 209, - Oacute: 211, - Ocirc: 212, - Ograve: 210, - Oslash: 216, - Otilde: 213, - Ouml: 214, - THORN: 222, - Uacute: 218, - Ucirc: 219, - Ugrave: 217, - Uuml: 220, - Yacute: 221, - aacute: 225, - acirc: 226, - aelig: 230, - agrave: 224, - aring: 229, - atilde: 227, - auml: 228, - ccedil: 231, - eacute: 233, - ecirc: 234, - egrave: 232, - eth: 240, - euml: 235, - iacute: 237, - icirc: 238, - igrave: 236, - iuml: 239, - ntilde: 241, - oacute: 243, - ocirc: 244, - ograve: 242, - oslash: 248, - otilde: 245, - ouml: 246, - szlig: 223, - thorn: 254, - uacute: 250, - ucirc: 251, - ugrave: 249, - uuml: 252, - yacute: 253, - yuml: 255, - copy: 169, - reg: 174, - nbsp: 160, - iexcl: 161, - cent: 162, - pound: 163, - curren: 164, - yen: 165, - brvbar: 166, - sect: 167, - uml: 168, - ordf: 170, - laquo: 171, - not: 172, - shy: 173, - macr: 175, - deg: 176, - plusmn: 177, - sup1: 185, - sup2: 178, - sup3: 179, - acute: 180, - micro: 181, - para: 182, - middot: 183, - cedil: 184, - ordm: 186, - raquo: 187, - frac14: 188, - frac12: 189, - frac34: 190, - iquest: 191, - times: 215, - divide: 247, - OElig: 338, - oelig: 339, - Scaron: 352, - scaron: 353, - Yuml: 376, - fnof: 402, - circ: 710, - tilde: 732, - Alpha: 913, - Beta: 914, - Gamma: 915, - Delta: 916, - Epsilon: 917, - Zeta: 918, - Eta: 919, - Theta: 920, - Iota: 921, - Kappa: 922, - Lambda: 923, - Mu: 924, - Nu: 925, - Xi: 926, - Omicron: 927, - Pi: 928, - Rho: 929, - Sigma: 931, - Tau: 932, - Upsilon: 933, - Phi: 934, - Chi: 935, - Psi: 936, - Omega: 937, - alpha: 945, - beta: 946, - gamma: 947, - delta: 948, - epsilon: 949, - zeta: 950, - eta: 951, - theta: 952, - iota: 953, - kappa: 954, - lambda: 955, - mu: 956, - nu: 957, - xi: 958, - omicron: 959, - pi: 960, - rho: 961, - sigmaf: 962, - sigma: 963, - tau: 964, - upsilon: 965, - phi: 966, - chi: 967, - psi: 968, - omega: 969, - thetasym: 977, - upsih: 978, - piv: 982, - ensp: 8194, - emsp: 8195, - thinsp: 8201, - zwnj: 8204, - zwj: 8205, - lrm: 8206, - rlm: 8207, - ndash: 8211, - mdash: 8212, - lsquo: 8216, - rsquo: 8217, - sbquo: 8218, - ldquo: 8220, - rdquo: 8221, - bdquo: 8222, - dagger: 8224, - Dagger: 8225, - bull: 8226, - hellip: 8230, - permil: 8240, - prime: 8242, - Prime: 8243, - lsaquo: 8249, - rsaquo: 8250, - oline: 8254, - frasl: 8260, - euro: 8364, - image: 8465, - weierp: 8472, - real: 8476, - trade: 8482, - alefsym: 8501, - larr: 8592, - uarr: 8593, - rarr: 8594, - darr: 8595, - harr: 8596, - crarr: 8629, - lArr: 8656, - uArr: 8657, - rArr: 8658, - dArr: 8659, - hArr: 8660, - forall: 8704, - part: 8706, - exist: 8707, - empty: 8709, - nabla: 8711, - isin: 8712, - notin: 8713, - ni: 8715, - prod: 8719, - sum: 8721, - minus: 8722, - lowast: 8727, - radic: 8730, - prop: 8733, - infin: 8734, - ang: 8736, - and: 8743, - or: 8744, - cap: 8745, - cup: 8746, - int: 8747, - there4: 8756, - sim: 8764, - cong: 8773, - asymp: 8776, - ne: 8800, - equiv: 8801, - le: 8804, - ge: 8805, - sub: 8834, - sup: 8835, - nsub: 8836, - sube: 8838, - supe: 8839, - oplus: 8853, - otimes: 8855, - perp: 8869, - sdot: 8901, - lceil: 8968, - rceil: 8969, - lfloor: 8970, - rfloor: 8971, - lang: 9001, - rang: 9002, - loz: 9674, - spades: 9824, - clubs: 9827, - hearts: 9829, - diams: 9830 - }; - Object.keys(sax$1.ENTITIES).forEach(function(key) { - var e = sax$1.ENTITIES[key]; - var s$1 = typeof e === "number" ? String.fromCharCode(e) : e; - sax$1.ENTITIES[key] = s$1; - }); - for (var s in sax$1.STATE) sax$1.STATE[sax$1.STATE[s]] = s; - S = sax$1.STATE; - function emit(parser, event, data) { - parser[event] && parser[event](data); + /** + * Merges two filters into one, based on the specified merge type. + * @param defaultFilter The default filter function. + * @param generatedFilter The generated filter function. + * @param mergeType The type of merge to perform. Can be 'and', 'or', or 'replace'. Default is 'and'. + * @returns A function that takes a `Document` as an argument and returns a boolean based on the merged filters, or `undefined` if both filters are empty. + */ + mergeFilters(defaultFilter, generatedFilter, mergeType = "and") { + if (isFilterEmpty(defaultFilter) && isFilterEmpty(generatedFilter)) return void 0; + if (isFilterEmpty(defaultFilter) || mergeType === "replace") { + if (isFilterEmpty(generatedFilter)) return void 0; + return generatedFilter; + } + if (isFilterEmpty(generatedFilter)) { + if (mergeType === "and") return void 0; + return defaultFilter; + } + if (mergeType === "and") return (document) => defaultFilter(document) && generatedFilter(document); + else if (mergeType === "or") return (document) => defaultFilter(document) || generatedFilter(document); + else throw new Error("Unknown merge type"); + } +}; + +//#endregion + +//# sourceMappingURL=functional.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/structured_query/index.js + + + + + + +//#region src/structured_query/index.ts +var structured_query_exports = {}; +__export(structured_query_exports, { + BaseTranslator: () => BaseTranslator, + BasicTranslator: () => BasicTranslator, + Comparators: () => Comparators, + Comparison: () => Comparison, + Expression: () => Expression, + FilterDirective: () => FilterDirective, + FunctionalTranslator: () => FunctionalTranslator, + Operation: () => Operation, + Operators: () => Operators, + StructuredQuery: () => StructuredQuery, + Visitor: () => Visitor, + castValue: () => castValue, + isBoolean: () => isBoolean, + isFilterEmpty: () => isFilterEmpty, + isFloat: () => isFloat, + isInt: () => isInt, + isObject: () => isObject, + isString: () => isString +}); + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tools/types.js + + + +//#region src/tools/types.ts +/** +* Confirm whether the inputted tool is an instance of `StructuredToolInterface`. +* +* @param {StructuredToolInterface | JSONSchema | undefined} tool The tool to check if it is an instance of `StructuredToolInterface`. +* @returns {tool is StructuredToolInterface} Whether the inputted tool is an instance of `StructuredToolInterface`. +*/ +function isStructuredTool(tool) { + return tool !== void 0 && Array.isArray(tool.lc_namespace); +} +/** +* Confirm whether the inputted tool is an instance of `RunnableToolLike`. +* +* @param {unknown | undefined} tool The tool to check if it is an instance of `RunnableToolLike`. +* @returns {tool is RunnableToolLike} Whether the inputted tool is an instance of `RunnableToolLike`. +*/ +function isRunnableToolLike(tool) { + return tool !== void 0 && Runnable.isRunnable(tool) && "lc_name" in tool.constructor && typeof tool.constructor.lc_name === "function" && tool.constructor.lc_name() === "RunnableToolLike"; +} +/** +* Confirm whether or not the tool contains the necessary properties to be considered a `StructuredToolParams`. +* +* @param {unknown | undefined} tool The object to check if it is a `StructuredToolParams`. +* @returns {tool is StructuredToolParams} Whether the inputted object is a `StructuredToolParams`. +*/ +function isStructuredToolParams(tool) { + return !!tool && typeof tool === "object" && "name" in tool && "schema" in tool && (isInteropZodSchema(tool.schema) || tool.schema != null && typeof tool.schema === "object" && "type" in tool.schema && typeof tool.schema.type === "string" && [ + "null", + "boolean", + "object", + "array", + "number", + "string" + ].includes(tool.schema.type)); +} +/** +* Whether or not the tool is one of StructuredTool, RunnableTool or StructuredToolParams. +* It returns `is StructuredToolParams` since that is the most minimal interface of the three, +* while still containing the necessary properties to be passed to a LLM for tool calling. +* +* @param {unknown | undefined} tool The tool to check if it is a LangChain tool. +* @returns {tool is StructuredToolParams} Whether the inputted tool is a LangChain tool. +*/ +function isLangChainTool(tool) { + return isStructuredToolParams(tool) || isRunnableToolLike(tool) || isStructuredTool(tool); +} + +//#endregion + +//# sourceMappingURL=types.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tools/index.js + + + + + + + + + + + + + + + + +//#region src/tools/index.ts +var tools_exports = {}; +__export(tools_exports, { + BaseToolkit: () => BaseToolkit, + DynamicStructuredTool: () => tools_DynamicStructuredTool, + DynamicTool: () => tools_DynamicTool, + StructuredTool: () => StructuredTool, + Tool: () => Tool, + ToolInputParsingException: () => ToolInputParsingException, + isLangChainTool: () => isLangChainTool, + isRunnableToolLike: () => isRunnableToolLike, + isStructuredTool: () => isStructuredTool, + isStructuredToolParams: () => isStructuredToolParams, + tool: () => tool +}); +/** +* Base class for Tools that accept input of any shape defined by a Zod schema. +*/ +var StructuredTool = class extends BaseLangChain { + /** + * Optional provider-specific extra fields for the tool. + * + * This is used to pass provider-specific configuration that doesn't fit into + * standard tool fields. + */ + extras; + /** + * Whether to return the tool's output directly. + * + * Setting this to true means that after the tool is called, + * an agent should stop looping. + */ + returnDirect = false; + verboseParsingErrors = false; + get lc_namespace() { + return ["langchain", "tools"]; } - function emitNode(parser, nodeType, data) { - if (parser.textNode) closeText(parser); - emit(parser, nodeType, data); + /** + * The tool response format. + * + * If "content" then the output of the tool is interpreted as the contents of a + * ToolMessage. If "content_and_artifact" then the output is expected to be a + * two-tuple corresponding to the (content, artifact) of a ToolMessage. + * + * @default "content" + */ + responseFormat = "content"; + /** + * Default config object for the tool runnable. + */ + defaultConfig; + constructor(fields) { + super(fields ?? {}); + this.verboseParsingErrors = fields?.verboseParsingErrors ?? this.verboseParsingErrors; + this.responseFormat = fields?.responseFormat ?? this.responseFormat; + this.defaultConfig = fields?.defaultConfig ?? this.defaultConfig; + this.metadata = fields?.metadata ?? this.metadata; + this.extras = fields?.extras ?? this.extras; } - function closeText(parser) { - parser.textNode = textopts(parser.opt, parser.textNode); - if (parser.textNode) emit(parser, "ontext", parser.textNode); - parser.textNode = ""; + /** + * Invokes the tool with the provided input and configuration. + * @param input The input for the tool. + * @param config Optional configuration for the tool. + * @returns A Promise that resolves with the tool's output. + */ + async invoke(input, config) { + let toolInput; + let enrichedConfig = ensureConfig(mergeConfigs(this.defaultConfig, config)); + if (_isToolCall(input)) { + toolInput = input.args; + enrichedConfig = { + ...enrichedConfig, + toolCall: input + }; + } else toolInput = input; + return this.call(toolInput, enrichedConfig); } - function textopts(opt, text) { - if (opt.trim) text = text.trim(); - if (opt.normalize) text = text.replace(/\s+/g, " "); - return text; + /** + * @deprecated Use .invoke() instead. Will be removed in 0.3.0. + * + * Calls the tool with the provided argument, configuration, and tags. It + * parses the input according to the schema, handles any errors, and + * manages callbacks. + * @param arg The input argument for the tool. + * @param configArg Optional configuration or callbacks for the tool. + * @param tags Optional tags for the tool. + * @returns A Promise that resolves with a string. + */ + async call(arg, configArg, tags) { + const inputForValidation = _isToolCall(arg) ? arg.args : arg; + let parsed; + if (isInteropZodSchema(this.schema)) try { + parsed = await interopParseAsync(this.schema, inputForValidation); + } catch (e) { + let message = `Received tool input did not match expected schema`; + if (this.verboseParsingErrors) message = `${message}\nDetails: ${e.message}`; + if (isInteropZodError(e)) message = `${message}\n\n${prettifyError(e)}`; + throw new ToolInputParsingException(message, JSON.stringify(arg)); + } + else { + const result$1 = validate_validate(inputForValidation, this.schema); + if (!result$1.valid) { + let message = `Received tool input did not match expected schema`; + if (this.verboseParsingErrors) message = `${message}\nDetails: ${result$1.errors.map((e) => `${e.keywordLocation}: ${e.error}`).join("\n")}`; + throw new ToolInputParsingException(message, JSON.stringify(arg)); + } + parsed = inputForValidation; + } + const config = parseCallbackConfigArg(configArg); + const callbackManager_ = CallbackManager.configure(config.callbacks, this.callbacks, config.tags || tags, this.tags, config.metadata, this.metadata, { verbose: this.verbose }); + const runManager = await callbackManager_?.handleToolStart(this.toJSON(), typeof arg === "string" ? arg : JSON.stringify(arg), config.runId, void 0, void 0, void 0, config.runName); + delete config.runId; + let result; + try { + result = await this._call(parsed, runManager, config); + } catch (e) { + await runManager?.handleToolError(e); + throw e; + } + let content; + let artifact; + if (this.responseFormat === "content_and_artifact") if (Array.isArray(result) && result.length === 2) [content, artifact] = result; + else throw new Error(`Tool response format is "content_and_artifact" but the output was not a two-tuple.\nResult: ${JSON.stringify(result)}`); + else content = result; + let toolCallId; + if (_isToolCall(arg)) toolCallId = arg.id; + if (!toolCallId && _configHasToolCallId(config)) toolCallId = config.toolCall.id; + const formattedOutput = _formatToolOutput({ + content, + artifact, + toolCallId, + name: this.name, + metadata: this.metadata + }); + await runManager?.handleToolEnd(formattedOutput); + return formattedOutput; } - function error(parser, er) { - closeText(parser); - if (parser.trackPosition) er += "\nLine: " + parser.line + "\nColumn: " + parser.column + "\nChar: " + parser.c; - er = new Error(er); - parser.error = er; - emit(parser, "onerror", er); - return parser; +}; +/** +* Base class for Tools that accept input as a string. +*/ +var Tool = class extends StructuredTool { + schema = objectType({ input: stringType().optional() }).transform((obj) => obj.input); + constructor(fields) { + super(fields); } - function end(parser) { - if (parser.sawRoot && !parser.closedRoot) strictFail(parser, "Unclosed root tag"); - if (parser.state !== S.BEGIN && parser.state !== S.BEGIN_WHITESPACE && parser.state !== S.TEXT) error(parser, "Unexpected end"); - closeText(parser); - parser.c = ""; - parser.closed = true; - emit(parser, "onend"); - SAXParser.call(parser, parser.strict, parser.opt); - return parser; + /** + * @deprecated Use .invoke() instead. Will be removed in 0.3.0. + * + * Calls the tool with the provided argument and callbacks. It handles + * string inputs specifically. + * @param arg The input argument for the tool, which can be a string, undefined, or an input of the tool's schema. + * @param callbacks Optional callbacks for the tool. + * @returns A Promise that resolves with a string. + */ + call(arg, callbacks) { + const structuredArg = typeof arg === "string" || arg == null ? { input: arg } : arg; + return super.call(structuredArg, callbacks); } - function strictFail(parser, message) { - if (typeof parser !== "object" || !(parser instanceof SAXParser)) throw new Error("bad call to strictFail"); - if (parser.strict) error(parser, message); +}; +/** +* A tool that can be created dynamically from a function, name, and description. +*/ +var tools_DynamicTool = class extends Tool { + static lc_name() { + return "DynamicTool"; } - function newTag(parser) { - if (!parser.strict) parser.tagName = parser.tagName[parser.looseCase](); - var parent = parser.tags[parser.tags.length - 1] || parser; - var tag = parser.tag = { - name: parser.tagName, - attributes: {} - }; - if (parser.opt.xmlns) tag.ns = parent.ns; - parser.attribList.length = 0; - emitNode(parser, "onopentagstart", tag); + name; + description; + func; + constructor(fields) { + super(fields); + this.name = fields.name; + this.description = fields.description; + this.func = fields.func; + this.returnDirect = fields.returnDirect ?? this.returnDirect; } - function qname(name, attribute) { - var i = name.indexOf(":"); - var qualName = i < 0 ? ["", name] : name.split(":"); - var prefix = qualName[0]; - var local = qualName[1]; - if (attribute && name === "xmlns") { - prefix = "xmlns"; - local = ""; - } - return { - prefix, - local - }; + /** + * @deprecated Use .invoke() instead. Will be removed in 0.3.0. + */ + async call(arg, configArg) { + const config = parseCallbackConfigArg(configArg); + if (config.runName === void 0) config.runName = this.name; + return super.call(arg, config); } - function attrib(parser) { - if (!parser.strict) parser.attribName = parser.attribName[parser.looseCase](); - if (parser.attribList.indexOf(parser.attribName) !== -1 || parser.tag.attributes.hasOwnProperty(parser.attribName)) { - parser.attribName = parser.attribValue = ""; - return; - } - if (parser.opt.xmlns) { - var qn = qname(parser.attribName, true); - var prefix = qn.prefix; - var local = qn.local; - if (prefix === "xmlns") if (local === "xml" && parser.attribValue !== XML_NAMESPACE) strictFail(parser, "xml: prefix must be bound to " + XML_NAMESPACE + "\nActual: " + parser.attribValue); - else if (local === "xmlns" && parser.attribValue !== XMLNS_NAMESPACE) strictFail(parser, "xmlns: prefix must be bound to " + XMLNS_NAMESPACE + "\nActual: " + parser.attribValue); - else { - var tag = parser.tag; - var parent = parser.tags[parser.tags.length - 1] || parser; - if (tag.ns === parent.ns) tag.ns = Object.create(parent.ns); - tag.ns[local] = parser.attribValue; - } - parser.attribList.push([parser.attribName, parser.attribValue]); - } else { - parser.tag.attributes[parser.attribName] = parser.attribValue; - emitNode(parser, "onattribute", { - name: parser.attribName, - value: parser.attribValue - }); - } - parser.attribName = parser.attribValue = ""; + /** @ignore */ + async _call(input, runManager, parentConfig) { + return this.func(input, runManager, parentConfig); } - function openTag(parser, selfClosing) { - if (parser.opt.xmlns) { - var tag = parser.tag; - var qn = qname(parser.tagName); - tag.prefix = qn.prefix; - tag.local = qn.local; - tag.uri = tag.ns[qn.prefix] || ""; - if (tag.prefix && !tag.uri) { - strictFail(parser, "Unbound namespace prefix: " + JSON.stringify(parser.tagName)); - tag.uri = qn.prefix; - } - var parent = parser.tags[parser.tags.length - 1] || parser; - if (tag.ns && parent.ns !== tag.ns) Object.keys(tag.ns).forEach(function(p) { - emitNode(parser, "onopennamespace", { - prefix: p, - uri: tag.ns[p] +}; +/** +* A tool that can be created dynamically from a function, name, and +* description, designed to work with structured data. It extends the +* StructuredTool class and overrides the _call method to execute the +* provided function when the tool is called. +* +* Schema can be passed as Zod or JSON schema. The tool will not validate +* input if JSON schema is passed. +* +* @template SchemaT The input schema type for the tool (Zod schema or JSON schema). Defaults to `ToolInputSchemaBase`. +* @template SchemaOutputT The output type derived from the schema after parsing/validation. Defaults to `ToolInputSchemaOutputType`. +* @template SchemaInputT The input type derived from the schema before parsing. Defaults to `ToolInputSchemaInputType`. +* @template ToolOutputT The return type of the tool's function. Defaults to `ToolOutputType`. +* @template NameT The literal type of the tool name (for discriminated union support). Defaults to `string`. +*/ +var tools_DynamicStructuredTool = class extends StructuredTool { + static lc_name() { + return "DynamicStructuredTool"; + } + description; + func; + schema; + constructor(fields) { + super(fields); + this.name = fields.name; + this.description = fields.description; + this.func = fields.func; + this.returnDirect = fields.returnDirect ?? this.returnDirect; + this.schema = fields.schema; + } + /** + * @deprecated Use .invoke() instead. Will be removed in 0.3.0. + */ + async call(arg, configArg, tags) { + const config = parseCallbackConfigArg(configArg); + if (config.runName === void 0) config.runName = this.name; + return super.call(arg, config, tags); + } + _call(arg, runManager, parentConfig) { + return this.func(arg, runManager, parentConfig); + } +}; +/** +* Abstract base class for toolkits in LangChain. Toolkits are collections +* of tools that agents can use. Subclasses must implement the `tools` +* property to provide the specific tools for the toolkit. +*/ +var BaseToolkit = class { + getTools() { + return this.tools; + } +}; +function tool(func, fields) { + const isSimpleStringSchema = isSimpleStringZodSchema(fields.schema); + const isStringJSONSchema = validatesOnlyStrings(fields.schema); + if (!fields.schema || isSimpleStringSchema || isStringJSONSchema) return new tools_DynamicTool({ + ...fields, + description: fields.description ?? fields.schema?.description ?? `${fields.name} tool`, + func: async (input, runManager, config) => { + return new Promise((resolve, reject) => { + const childConfig = config_patchConfig(config, { callbacks: runManager?.getChild() }); + async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(childConfig), async () => { + try { + resolve(func(input, childConfig)); + } catch (e) { + reject(e); + } }); }); - for (var i = 0, l = parser.attribList.length; i < l; i++) { - var nv = parser.attribList[i]; - var name = nv[0]; - var value = nv[1]; - var qualName = qname(name, true); - var prefix = qualName.prefix; - var local = qualName.local; - var uri = prefix === "" ? "" : tag.ns[prefix] || ""; - var a = { - name, - value, - prefix, - local, - uri + } + }); + const schema = fields.schema; + const description = fields.description ?? fields.schema.description ?? `${fields.name} tool`; + return new tools_DynamicStructuredTool({ + ...fields, + description, + schema, + func: async (input, runManager, config) => { + return new Promise((resolve, reject) => { + let listener; + const cleanup = () => { + if (config?.signal && listener) config.signal.removeEventListener("abort", listener); }; - if (prefix && prefix !== "xmlns" && !uri) { - strictFail(parser, "Unbound namespace prefix: " + JSON.stringify(prefix)); - a.uri = prefix; + if (config?.signal) { + listener = () => { + cleanup(); + reject(getAbortSignalError(config.signal)); + }; + config.signal.addEventListener("abort", listener); } - parser.tag.attributes[name] = a; - emitNode(parser, "onattribute", a); - } - parser.attribList.length = 0; + const childConfig = config_patchConfig(config, { callbacks: runManager?.getChild() }); + async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(config_pickRunnableConfigKeys(childConfig), async () => { + try { + const result = await func(input, childConfig); + /** + * If the signal is aborted, we don't want to resolve the promise + * as the promise is already rejected. + */ + if (config?.signal?.aborted) { + cleanup(); + return; + } + cleanup(); + resolve(result); + } catch (e) { + cleanup(); + reject(e); + } + }); + }); + } + }); +} +function _formatToolOutput(params) { + const { content, artifact, toolCallId, metadata } = params; + if (toolCallId && !isDirectToolOutput(content)) if (typeof content === "string" || Array.isArray(content) && content.every((item) => typeof item === "object")) return new ToolMessage({ + status: "success", + content, + artifact, + tool_call_id: toolCallId, + name: params.name, + metadata + }); + else return new ToolMessage({ + status: "success", + content: tools_stringify(content), + artifact, + tool_call_id: toolCallId, + name: params.name, + metadata + }); + else return content; +} +function tools_stringify(content) { + try { + return JSON.stringify(content, null, 2) ?? ""; + } catch (_noOp) { + return `${content}`; + } +} + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/tracers/run_collector.js + + + +//#region src/tracers/run_collector.ts +var run_collector_exports = {}; +__export(run_collector_exports, { RunCollectorCallbackHandler: () => RunCollectorCallbackHandler }); +/** +* A callback handler that collects traced runs and makes it easy to fetch the traced run object from calls through any langchain object. +* For instance, it makes it easy to fetch the run ID and then do things with that, such as log feedback. +*/ +var RunCollectorCallbackHandler = class extends BaseTracer { + /** The name of the callback handler. */ + name = "run_collector"; + /** The ID of the example. */ + exampleId; + /** An array of traced runs. */ + tracedRuns; + /** + * Creates a new instance of the RunCollectorCallbackHandler class. + * @param exampleId The ID of the example. + */ + constructor({ exampleId } = {}) { + super({ _awaitHandler: true }); + this.exampleId = exampleId; + this.tracedRuns = []; + } + /** + * Persists the given run object. + * @param run The run object to persist. + */ + async persistRun(run) { + const run_ = { ...run }; + run_.reference_example_id = this.exampleId; + this.tracedRuns.push(run_); + } +}; + +//#endregion + +//# sourceMappingURL=run_collector.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/types/stream.js +//#region src/types/stream.ts +var stream_stream_exports = {}; + +//#endregion + +//# sourceMappingURL=stream.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/chunk_array.js + + +//#region src/utils/chunk_array.ts +var chunk_array_exports = {}; +__export(chunk_array_exports, { chunkArray: () => chunkArray }); +const chunkArray = (arr, chunkSize) => arr.reduce((chunks, elem, index) => { + const chunkIndex = Math.floor(index / chunkSize); + const chunk = chunks[chunkIndex] || []; + chunks[chunkIndex] = chunk.concat([elem]); + return chunks; +}, []); + +//#endregion + +//# sourceMappingURL=chunk_array.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/context.js + + +//#region src/utils/context.ts +var context_exports = {}; +__export(context_exports, { context: () => context }); +/** +* A tagged template function for creating formatted strings. +* +* This utility provides a clean, template literal-based API for string formatting +* that can be used for prompts, descriptions, and other text formatting needs. +* +* It automatically handles whitespace normalization and indentation, making it +* ideal for multi-line strings in code. +* +* When using this utility, it will: +* - Strip common leading indentation from all lines +* - Trim leading/trailing whitespace +* - Align multi-line interpolated values to match indentation +* - Support escape sequences: `\\n` (newline), `\\`` (backtick), `\\$` (dollar), `\\{` (brace) +* +* @example +* ```typescript +* import { context } from "@langchain/core/utils/context"; +* +* const role = "agent"; +* const prompt = context` +* You are an ${role}. +* Your task is to help users. +* `; +* // Returns: "You are an agent.\nYour task is to help users." +* ``` +* +* @example +* ```typescript +* // Multi-line interpolated values are aligned +* const items = "- Item 1\n- Item 2\n- Item 3"; +* const message = context` +* Shopping list: +* ${items} +* End of list. +* `; +* // The items will be indented to match " " (4 spaces) +* ``` +*/ +function context(strings, ...values) { + const raw = strings.raw; + let result = ""; + for (let i = 0; i < raw.length; i++) { + const next = raw[i].replace(/\\\n[ \t]*/g, "").replace(/\\`/g, "`").replace(/\\\$/g, "$").replace(/\\\{/g, "{"); + result += next; + if (i < values.length) { + const value = alignValue(values[i], result); + result += typeof value === "string" ? value : JSON.stringify(value); } - parser.tag.isSelfClosing = !!selfClosing; - parser.sawRoot = true; - parser.tags.push(parser.tag); - emitNode(parser, "onopentag", parser.tag); - if (!selfClosing) { - if (!parser.noscript && parser.tagName.toLowerCase() === "script") parser.state = S.SCRIPT; - else parser.state = S.TEXT; - parser.tag = null; - parser.tagName = ""; + } + result = stripIndent(result); + result = result.trim(); + result = result.replace(/\\n/g, "\n"); + return result; +} +/** +* Adjusts the indentation of a multi-line interpolated value to match the current line. +* +* @param value - The interpolated value +* @param precedingText - The text that comes before this value +* @returns The value with adjusted indentation +*/ +function alignValue(value, precedingText) { + if (typeof value !== "string" || !value.includes("\n")) return value; + const currentLine = precedingText.slice(precedingText.lastIndexOf("\n") + 1); + const indentMatch = currentLine.match(/^(\s+)/); + if (indentMatch) { + const indent = indentMatch[1]; + return value.replace(/\n/g, `\n${indent}`); + } + return value; +} +/** +* Strips common leading indentation from all lines. +* +* @param text - The text to process +* @returns The text with common indentation removed +*/ +function stripIndent(text) { + const lines = text.split("\n"); + let minIndent = null; + for (const line of lines) { + const match = line.match(/^(\s+)\S+/); + if (match) { + const indent = match[1].length; + if (minIndent === null) minIndent = indent; + else minIndent = Math.min(minIndent, indent); } - parser.attribName = parser.attribValue = ""; - parser.attribList.length = 0; } - function closeTag(parser) { - if (!parser.tagName) { - strictFail(parser, "Weird empty close tag."); - parser.textNode += ""; - parser.state = S.TEXT; + if (minIndent === null) return text; + return lines.map((line) => line[0] === " " || line[0] === " " ? line.slice(minIndent) : line).join("\n"); +} + +//#endregion + +//# sourceMappingURL=context.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/event_source_parse.js + + + +//#region src/utils/event_source_parse.ts +var event_source_parse_exports = {}; +__export(event_source_parse_exports, { + EventStreamContentType: () => EventStreamContentType, + convertEventStreamToIterableReadableDataStream: () => convertEventStreamToIterableReadableDataStream, + getBytes: () => getBytes, + getLines: () => getLines, + getMessages: () => getMessages +}); +const EventStreamContentType = "text/event-stream"; +/** +* Converts a ReadableStream into a callback pattern. +* @param stream The input ReadableStream. +* @param onChunk A function that will be called on each new byte chunk in the stream. +* @returns {Promise} A promise that will be resolved when the stream closes. +*/ +async function getBytes(stream, onChunk) { + if (stream instanceof ReadableStream) { + const reader = stream.getReader(); + while (true) { + const result = await reader.read(); + if (result.done) { + onChunk(new Uint8Array(), true); + break; + } + onChunk(result.value); + } + } else try { + for await (const chunk of stream) onChunk(new Uint8Array(chunk)); + onChunk(new Uint8Array(), true); + } catch (e) { + throw new Error([ + "Parsing event source stream failed.", + "Ensure your implementation of fetch returns a web or Node readable stream.", + `Error: ${e.message}` + ].join("\n")); + } +} +var ControlChars = /* @__PURE__ */ function(ControlChars$1) { + ControlChars$1[ControlChars$1["NewLine"] = 10] = "NewLine"; + ControlChars$1[ControlChars$1["CarriageReturn"] = 13] = "CarriageReturn"; + ControlChars$1[ControlChars$1["Space"] = 32] = "Space"; + ControlChars$1[ControlChars$1["Colon"] = 58] = "Colon"; + return ControlChars$1; +}(ControlChars || {}); +/** +* Parses arbitary byte chunks into EventSource line buffers. +* Each line should be of the format "field: value" and ends with \r, \n, or \r\n. +* @param onLine A function that will be called on each new EventSource line. +* @returns A function that should be called for each incoming byte chunk. +*/ +function getLines(onLine) { + let buffer; + let position; + let fieldLength; + let discardTrailingNewline = false; + return function onChunk(arr, flush) { + if (flush) { + onLine(arr, 0, true); return; } - if (parser.script) { - if (parser.tagName !== "script") { - parser.script += ""; - parser.tagName = ""; - parser.state = S.SCRIPT; - return; + if (buffer === void 0) { + buffer = arr; + position = 0; + fieldLength = -1; + } else buffer = event_source_parse_concat(buffer, arr); + const bufLength = buffer.length; + let lineStart = 0; + while (position < bufLength) { + if (discardTrailingNewline) { + if (buffer[position] === ControlChars.NewLine) lineStart = ++position; + discardTrailingNewline = false; } - emitNode(parser, "onscript", parser.script); - parser.script = ""; + let lineEnd = -1; + for (; position < bufLength && lineEnd === -1; ++position) switch (buffer[position]) { + case ControlChars.Colon: + if (fieldLength === -1) fieldLength = position - lineStart; + break; + case ControlChars.CarriageReturn: discardTrailingNewline = true; + case ControlChars.NewLine: + lineEnd = position; + break; + } + if (lineEnd === -1) break; + onLine(buffer.subarray(lineStart, lineEnd), fieldLength); + lineStart = position; + fieldLength = -1; } - var t = parser.tags.length; - var tagName = parser.tagName; - if (!parser.strict) tagName = tagName[parser.looseCase](); - var closeTo = tagName; - while (t--) { - var close = parser.tags[t]; - if (close.name !== closeTo) strictFail(parser, "Unexpected close tag"); - else break; + if (lineStart === bufLength) buffer = void 0; + else if (lineStart !== 0) { + buffer = buffer.subarray(lineStart); + position -= lineStart; } - if (t < 0) { - strictFail(parser, "Unmatched closing tag: " + parser.tagName); - parser.textNode += ""; - parser.state = S.TEXT; + }; +} +/** +* Parses line buffers into EventSourceMessages. +* @param onId A function that will be called on each `id` field. +* @param onRetry A function that will be called on each `retry` field. +* @param onMessage A function that will be called on each message. +* @returns A function that should be called for each incoming line buffer. +*/ +function getMessages(onMessage, onId, onRetry) { + let message = newMessage(); + const decoder = new TextDecoder(); + return function onLine(line, fieldLength, flush) { + if (flush) { + if (!isEmpty(message)) { + onMessage?.(message); + message = newMessage(); + } return; } - parser.tagName = tagName; - var s$1 = parser.tags.length; - while (s$1-- > t) { - var tag = parser.tag = parser.tags.pop(); - parser.tagName = parser.tag.name; - emitNode(parser, "onclosetag", parser.tagName); - var x = {}; - for (var i in tag.ns) x[i] = tag.ns[i]; - var parent = parser.tags[parser.tags.length - 1] || parser; - if (parser.opt.xmlns && tag.ns !== parent.ns) Object.keys(tag.ns).forEach(function(p) { - var n = tag.ns[p]; - emitNode(parser, "onclosenamespace", { - prefix: p, - uri: n - }); - }); + if (line.length === 0) { + onMessage?.(message); + message = newMessage(); + } else if (fieldLength > 0) { + const field = decoder.decode(line.subarray(0, fieldLength)); + const valueOffset = fieldLength + (line[fieldLength + 1] === ControlChars.Space ? 2 : 1); + const value = decoder.decode(line.subarray(valueOffset)); + switch (field) { + case "data": + message.data = message.data ? message.data + "\n" + value : value; + break; + case "event": + message.event = value; + break; + case "id": + onId?.(message.id = value); + break; + case "retry": { + const retry = parseInt(value, 10); + if (!Number.isNaN(retry)) onRetry?.(message.retry = retry); + break; + } + } } - if (t === 0) parser.closedRoot = true; - parser.tagName = parser.attribValue = parser.attribName = ""; - parser.attribList.length = 0; - parser.state = S.TEXT; + }; +} +function event_source_parse_concat(a, b) { + const res = new Uint8Array(a.length + b.length); + res.set(a); + res.set(b, a.length); + return res; +} +function newMessage() { + return { + data: "", + event: "", + id: "", + retry: void 0 + }; +} +function convertEventStreamToIterableReadableDataStream(stream, onMetadataEvent) { + const dataStream = new ReadableStream({ async start(controller) { + const enqueueLine = getMessages((msg) => { + if (msg.event === "error") throw new Error(msg.data ?? "Unspecified event streaming error."); + else if (msg.event === "metadata") onMetadataEvent?.(msg); + else if (msg.data) controller.enqueue(msg.data); + }); + const onLine = (line, fieldLength, flush) => { + enqueueLine(line, fieldLength, flush); + if (flush) controller.close(); + }; + await getBytes(stream, getLines(onLine)); + } }); + return IterableReadableStream.fromReadableStream(dataStream); +} +function isEmpty(message) { + return message.data === "" && message.event === "" && message.id === "" && message.retry === void 0; +} + +//#endregion + +//# sourceMappingURL=event_source_parse.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/format.js +//#region src/utils/format.ts +var format_exports = {}; + +//#endregion + +//# sourceMappingURL=format.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/function_calling.js + + + + +//#region src/utils/function_calling.ts +var function_calling_exports = {}; +__export(function_calling_exports, { + convertToOpenAIFunction: () => convertToOpenAIFunction, + convertToOpenAITool: () => convertToOpenAITool, + isLangChainTool: () => isLangChainTool, + isRunnableToolLike: () => isRunnableToolLike, + isStructuredTool: () => isStructuredTool, + isStructuredToolParams: () => isStructuredToolParams +}); +/** +* Formats a `StructuredTool` or `RunnableToolLike` instance into a format +* that is compatible with OpenAI function calling. If `StructuredTool` or +* `RunnableToolLike` has a zod schema, the output will be converted into a +* JSON schema, which is then used as the parameters for the OpenAI tool. +* +* @param {StructuredToolInterface | RunnableToolLike} tool The tool to convert to an OpenAI function. +* @returns {FunctionDefinition} The inputted tool in OpenAI function format. +*/ +function convertToOpenAIFunction(tool, fields) { + const fieldsCopy = typeof fields === "number" ? void 0 : fields; + return { + name: tool.name, + description: tool.description, + parameters: toJsonSchema(tool.schema), + ...fieldsCopy?.strict !== void 0 ? { strict: fieldsCopy.strict } : {} + }; +} +/** +* Formats a `StructuredTool` or `RunnableToolLike` instance into a +* format that is compatible with OpenAI tool calling. If `StructuredTool` or +* `RunnableToolLike` has a zod schema, the output will be converted into a +* JSON schema, which is then used as the parameters for the OpenAI tool. +* +* @param {StructuredToolInterface | Record | RunnableToolLike} tool The tool to convert to an OpenAI tool. +* @returns {ToolDefinition} The inputted tool in OpenAI tool format. +*/ +function convertToOpenAITool(tool, fields) { + const fieldsCopy = typeof fields === "number" ? void 0 : fields; + let toolDef; + if (isLangChainTool(tool)) toolDef = { + type: "function", + function: convertToOpenAIFunction(tool) + }; + else toolDef = tool; + if (fieldsCopy?.strict !== void 0) toolDef.function.strict = fieldsCopy.strict; + return toolDef; +} + +//#endregion + +//# sourceMappingURL=function_calling.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/ml-distance/similarities.js +//#region src/utils/ml-distance/similarities.ts +/** +* Returns the average of cosine distances between vectors a and b +* @param a - first vector +* @param b - second vector +* +*/ +function cosine(a, b) { + let p = 0; + let p2 = 0; + let q2 = 0; + for (let i = 0; i < a.length; i++) { + p += a[i] * b[i]; + p2 += a[i] * a[i]; + q2 += b[i] * b[i]; } - function parseEntity(parser) { - var entity = parser.entity; - var entityLC = entity.toLowerCase(); - var num; - var numStr = ""; - if (parser.ENTITIES[entity]) return parser.ENTITIES[entity]; - if (parser.ENTITIES[entityLC]) return parser.ENTITIES[entityLC]; - entity = entityLC; - if (entity.charAt(0) === "#") if (entity.charAt(1) === "x") { - entity = entity.slice(2); - num = parseInt(entity, 16); - numStr = num.toString(16); - } else { - entity = entity.slice(1); - num = parseInt(entity, 10); - numStr = num.toString(10); - } - entity = entity.replace(/^0+/, ""); - if (isNaN(num) || numStr.toLowerCase() !== entity) { - strictFail(parser, "Invalid character entity"); - return "&" + parser.entity + ";"; - } - return String.fromCodePoint(num); + return p / (Math.sqrt(p2) * Math.sqrt(q2)); +} + +//#endregion + +//# sourceMappingURL=similarities.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/ml-distance/distances.js +//#region src/utils/ml-distance/distances.ts +/** +*Returns the Inner Product similarity between vectors a and b +* @link [Inner Product Similarity algorithm](https://www.naun.org/main/NAUN/ijmmas/mmmas-49.pdf) +* @param a - first vector +* @param b - second vector +* +*/ +function innerProduct(a, b) { + let ans = 0; + for (let i = 0; i < a.length; i++) ans += a[i] * b[i]; + return ans; +} + +//#endregion + +//# sourceMappingURL=distances.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/ml-distance-euclidean/euclidean.js +//#region src/utils/ml-distance-euclidean/euclidean.ts +function squaredEuclidean(p, q) { + let d = 0; + for (let i = 0; i < p.length; i++) d += (p[i] - q[i]) * (p[i] - q[i]); + return d; +} +function euclidean(p, q) { + return Math.sqrt(squaredEuclidean(p, q)); +} + +//#endregion + +//# sourceMappingURL=euclidean.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/math.js + + + + + +//#region src/utils/math.ts +var math_exports = {}; +__export(math_exports, { + cosineSimilarity: () => cosineSimilarity, + euclideanDistance: () => euclideanDistance, + innerProduct: () => innerProduct$1, + matrixFunc: () => matrixFunc, + maximalMarginalRelevance: () => maximalMarginalRelevance, + normalize: () => normalize +}); +/** +* Apply a row-wise function between two matrices with the same number of columns. +* +* @param {number[][]} X - The first matrix. +* @param {number[][]} Y - The second matrix. +* @param {VectorFunction} func - The function to apply. +* +* @throws {Error} If the number of columns in X and Y are not the same. +* +* @returns {number[][] | [[]]} A matrix where each row represents the result of applying the function between the corresponding rows of X and Y. +*/ +function matrixFunc(X, Y, func) { + if (X.length === 0 || X[0].length === 0 || Y.length === 0 || Y[0].length === 0) return [[]]; + if (X[0].length !== Y[0].length) throw new Error(`Number of columns in X and Y must be the same. X has shape ${[X.length, X[0].length]} and Y has shape ${[Y.length, Y[0].length]}.`); + return X.map((xVector) => Y.map((yVector) => func(xVector, yVector)).map((similarity) => Number.isNaN(similarity) ? 0 : similarity)); +} +function normalize(M, similarity = false) { + const max = matrixMaxVal(M); + return M.map((row) => row.map((val) => similarity ? 1 - val / max : val / max)); +} +/** +* This function calculates the row-wise cosine similarity between two matrices with the same number of columns. +* +* @param {number[][]} X - The first matrix. +* @param {number[][]} Y - The second matrix. +* +* @throws {Error} If the number of columns in X and Y are not the same. +* +* @returns {number[][] | [[]]} A matrix where each row represents the cosine similarity values between the corresponding rows of X and Y. +*/ +function cosineSimilarity(X, Y) { + return matrixFunc(X, Y, cosine); +} +function innerProduct$1(X, Y) { + return matrixFunc(X, Y, innerProduct); +} +function euclideanDistance(X, Y) { + return matrixFunc(X, Y, euclidean); +} +/** +* This function implements the Maximal Marginal Relevance algorithm +* to select a set of embeddings that maximizes the diversity and relevance to a query embedding. +* +* @param {number[]|number[][]} queryEmbedding - The query embedding. +* @param {number[][]} embeddingList - The list of embeddings to select from. +* @param {number} [lambda=0.5] - The trade-off parameter between relevance and diversity. +* @param {number} [k=4] - The maximum number of embeddings to select. +* +* @returns {number[]} The indexes of the selected embeddings in the embeddingList. +*/ +function maximalMarginalRelevance(queryEmbedding, embeddingList, lambda = .5, k = 4) { + if (Math.min(k, embeddingList.length) <= 0) return []; + const queryEmbeddingExpanded = Array.isArray(queryEmbedding[0]) ? queryEmbedding : [queryEmbedding]; + const similarityToQuery = cosineSimilarity(queryEmbeddingExpanded, embeddingList)[0]; + const mostSimilarEmbeddingIndex = argMax(similarityToQuery).maxIndex; + const selectedEmbeddings = [embeddingList[mostSimilarEmbeddingIndex]]; + const selectedEmbeddingsIndexes = [mostSimilarEmbeddingIndex]; + while (selectedEmbeddingsIndexes.length < Math.min(k, embeddingList.length)) { + let bestScore = -Infinity; + let bestIndex = -1; + const similarityToSelected = cosineSimilarity(embeddingList, selectedEmbeddings); + similarityToQuery.forEach((queryScore, queryScoreIndex) => { + if (selectedEmbeddingsIndexes.includes(queryScoreIndex)) return; + const maxSimilarityToSelected = Math.max(...similarityToSelected[queryScoreIndex]); + const score = lambda * queryScore - (1 - lambda) * maxSimilarityToSelected; + if (score > bestScore) { + bestScore = score; + bestIndex = queryScoreIndex; + } + }); + selectedEmbeddings.push(embeddingList[bestIndex]); + selectedEmbeddingsIndexes.push(bestIndex); + } + return selectedEmbeddingsIndexes; +} +/** +* Finds the index of the maximum value in the given array. +* @param {number[]} array - The input array. +* +* @returns {number} The index of the maximum value in the array. If the array is empty, returns -1. +*/ +function argMax(array) { + if (array.length === 0) return { + maxIndex: -1, + maxValue: NaN + }; + let maxValue = array[0]; + let maxIndex = 0; + for (let i = 1; i < array.length; i += 1) if (array[i] > maxValue) { + maxIndex = i; + maxValue = array[i]; + } + return { + maxIndex, + maxValue + }; +} +function matrixMaxVal(arrays) { + return arrays.reduce((acc, array) => Math.max(acc, argMax(array).maxValue), 0); +} + +//#endregion + +//# sourceMappingURL=math.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/chat_models.js + + + + + + + +//#region src/utils/testing/chat_models.ts +var FakeChatModel = class extends BaseChatModel { + _combineLLMOutput() { + return []; } - function beginWhiteSpace(parser, c) { - if (c === "<") { - parser.state = S.OPEN_WAKA; - parser.startTagPosition = parser.position; - } else if (!isWhitespace(c)) { - strictFail(parser, "Non-whitespace before first tag."); - parser.textNode = c; - parser.state = S.TEXT; - } + _llmType() { + return "fake"; } - function charAt(chunk, i) { - var result = ""; - if (i < chunk.length) result = chunk.charAt(i); - return result; + async _generate(messages, options, runManager) { + if (options?.stop?.length) return { generations: [{ + message: new AIMessage(options.stop[0]), + text: options.stop[0] + }] }; + const text = messages.map((m) => { + if (typeof m.content === "string") return m.content; + return JSON.stringify(m.content, null, 2); + }).join("\n"); + await runManager?.handleLLMNewToken(text); + return { + generations: [{ + message: new AIMessage(text), + text + }], + llmOutput: {} + }; } - function write(chunk) { - var parser = this; - if (this.error) throw this.error; - if (parser.closed) return error(parser, "Cannot write after close. Assign an onready handler."); - if (chunk === null) return end(parser); - if (typeof chunk === "object") chunk = chunk.toString(); - var i = 0; - var c = ""; - while (true) { - c = charAt(chunk, i++); - parser.c = c; - if (!c) break; - if (parser.trackPosition) { - parser.position++; - if (c === "\n") { - parser.line++; - parser.column = 0; - } else parser.column++; - } - switch (parser.state) { - case S.BEGIN: - parser.state = S.BEGIN_WHITESPACE; - if (c === "") continue; - beginWhiteSpace(parser, c); - continue; - case S.BEGIN_WHITESPACE: - beginWhiteSpace(parser, c); - continue; - case S.TEXT: - if (parser.sawRoot && !parser.closedRoot) { - var starti = i - 1; - while (c && c !== "<" && c !== "&") { - c = charAt(chunk, i++); - if (c && parser.trackPosition) { - parser.position++; - if (c === "\n") { - parser.line++; - parser.column = 0; - } else parser.column++; - } - } - parser.textNode += chunk.substring(starti, i - 1); - } - if (c === "<" && !(parser.sawRoot && parser.closedRoot && !parser.strict)) { - parser.state = S.OPEN_WAKA; - parser.startTagPosition = parser.position; - } else { - if (!isWhitespace(c) && (!parser.sawRoot || parser.closedRoot)) strictFail(parser, "Text data outside of root node."); - if (c === "&") parser.state = S.TEXT_ENTITY; - else parser.textNode += c; - } - continue; - case S.SCRIPT: - if (c === "<") parser.state = S.SCRIPT_ENDING; - else parser.script += c; - continue; - case S.SCRIPT_ENDING: - if (c === "/") parser.state = S.CLOSE_TAG; - else { - parser.script += "<" + c; - parser.state = S.SCRIPT; - } - continue; - case S.OPEN_WAKA: - if (c === "!") { - parser.state = S.SGML_DECL; - parser.sgmlDecl = ""; - } else if (isWhitespace(c)) {} else if (isMatch(nameStart, c)) { - parser.state = S.OPEN_TAG; - parser.tagName = c; - } else if (c === "/") { - parser.state = S.CLOSE_TAG; - parser.tagName = ""; - } else if (c === "?") { - parser.state = S.PROC_INST; - parser.procInstName = parser.procInstBody = ""; - } else { - strictFail(parser, "Unencoded <"); - if (parser.startTagPosition + 1 < parser.position) { - var pad = parser.position - parser.startTagPosition; - c = new Array(pad).join(" ") + c; - } - parser.textNode += "<" + c; - parser.state = S.TEXT; - } - continue; - case S.SGML_DECL: - if ((parser.sgmlDecl + c).toUpperCase() === CDATA) { - emitNode(parser, "onopencdata"); - parser.state = S.CDATA; - parser.sgmlDecl = ""; - parser.cdata = ""; - } else if (parser.sgmlDecl + c === "--") { - parser.state = S.COMMENT; - parser.comment = ""; - parser.sgmlDecl = ""; - } else if ((parser.sgmlDecl + c).toUpperCase() === DOCTYPE) { - parser.state = S.DOCTYPE; - if (parser.doctype || parser.sawRoot) strictFail(parser, "Inappropriately located doctype declaration"); - parser.doctype = ""; - parser.sgmlDecl = ""; - } else if (c === ">") { - emitNode(parser, "onsgmldeclaration", parser.sgmlDecl); - parser.sgmlDecl = ""; - parser.state = S.TEXT; - } else if (isQuote(c)) { - parser.state = S.SGML_DECL_QUOTED; - parser.sgmlDecl += c; - } else parser.sgmlDecl += c; - continue; - case S.SGML_DECL_QUOTED: - if (c === parser.q) { - parser.state = S.SGML_DECL; - parser.q = ""; - } - parser.sgmlDecl += c; - continue; - case S.DOCTYPE: - if (c === ">") { - parser.state = S.TEXT; - emitNode(parser, "ondoctype", parser.doctype); - parser.doctype = true; - } else { - parser.doctype += c; - if (c === "[") parser.state = S.DOCTYPE_DTD; - else if (isQuote(c)) { - parser.state = S.DOCTYPE_QUOTED; - parser.q = c; - } - } - continue; - case S.DOCTYPE_QUOTED: - parser.doctype += c; - if (c === parser.q) { - parser.q = ""; - parser.state = S.DOCTYPE; - } - continue; - case S.DOCTYPE_DTD: - parser.doctype += c; - if (c === "]") parser.state = S.DOCTYPE; - else if (isQuote(c)) { - parser.state = S.DOCTYPE_DTD_QUOTED; - parser.q = c; - } - continue; - case S.DOCTYPE_DTD_QUOTED: - parser.doctype += c; - if (c === parser.q) { - parser.state = S.DOCTYPE_DTD; - parser.q = ""; - } - continue; - case S.COMMENT: - if (c === "-") parser.state = S.COMMENT_ENDING; - else parser.comment += c; - continue; - case S.COMMENT_ENDING: - if (c === "-") { - parser.state = S.COMMENT_ENDED; - parser.comment = textopts(parser.opt, parser.comment); - if (parser.comment) emitNode(parser, "oncomment", parser.comment); - parser.comment = ""; - } else { - parser.comment += "-" + c; - parser.state = S.COMMENT; - } - continue; - case S.COMMENT_ENDED: - if (c !== ">") { - strictFail(parser, "Malformed comment"); - parser.comment += "--" + c; - parser.state = S.COMMENT; - } else parser.state = S.TEXT; - continue; - case S.CDATA: - if (c === "]") parser.state = S.CDATA_ENDING; - else parser.cdata += c; - continue; - case S.CDATA_ENDING: - if (c === "]") parser.state = S.CDATA_ENDING_2; - else { - parser.cdata += "]" + c; - parser.state = S.CDATA; - } - continue; - case S.CDATA_ENDING_2: - if (c === ">") { - if (parser.cdata) emitNode(parser, "oncdata", parser.cdata); - emitNode(parser, "onclosecdata"); - parser.cdata = ""; - parser.state = S.TEXT; - } else if (c === "]") parser.cdata += "]"; - else { - parser.cdata += "]]" + c; - parser.state = S.CDATA; - } - continue; - case S.PROC_INST: - if (c === "?") parser.state = S.PROC_INST_ENDING; - else if (isWhitespace(c)) parser.state = S.PROC_INST_BODY; - else parser.procInstName += c; - continue; - case S.PROC_INST_BODY: - if (!parser.procInstBody && isWhitespace(c)) continue; - else if (c === "?") parser.state = S.PROC_INST_ENDING; - else parser.procInstBody += c; - continue; - case S.PROC_INST_ENDING: - if (c === ">") { - emitNode(parser, "onprocessinginstruction", { - name: parser.procInstName, - body: parser.procInstBody - }); - parser.procInstName = parser.procInstBody = ""; - parser.state = S.TEXT; - } else { - parser.procInstBody += "?" + c; - parser.state = S.PROC_INST_BODY; - } - continue; - case S.OPEN_TAG: - if (isMatch(nameBody, c)) parser.tagName += c; - else { - newTag(parser); - if (c === ">") openTag(parser); - else if (c === "/") parser.state = S.OPEN_TAG_SLASH; - else { - if (!isWhitespace(c)) strictFail(parser, "Invalid character in tag name"); - parser.state = S.ATTRIB; - } - } - continue; - case S.OPEN_TAG_SLASH: - if (c === ">") { - openTag(parser, true); - closeTag(parser); - } else { - strictFail(parser, "Forward-slash in opening tag not followed by >"); - parser.state = S.ATTRIB; - } - continue; - case S.ATTRIB: - if (isWhitespace(c)) continue; - else if (c === ">") openTag(parser); - else if (c === "/") parser.state = S.OPEN_TAG_SLASH; - else if (isMatch(nameStart, c)) { - parser.attribName = c; - parser.attribValue = ""; - parser.state = S.ATTRIB_NAME; - } else strictFail(parser, "Invalid attribute name"); - continue; - case S.ATTRIB_NAME: - if (c === "=") parser.state = S.ATTRIB_VALUE; - else if (c === ">") { - strictFail(parser, "Attribute without value"); - parser.attribValue = parser.attribName; - attrib(parser); - openTag(parser); - } else if (isWhitespace(c)) parser.state = S.ATTRIB_NAME_SAW_WHITE; - else if (isMatch(nameBody, c)) parser.attribName += c; - else strictFail(parser, "Invalid attribute name"); - continue; - case S.ATTRIB_NAME_SAW_WHITE: - if (c === "=") parser.state = S.ATTRIB_VALUE; - else if (isWhitespace(c)) continue; - else { - strictFail(parser, "Attribute without value"); - parser.tag.attributes[parser.attribName] = ""; - parser.attribValue = ""; - emitNode(parser, "onattribute", { - name: parser.attribName, - value: "" - }); - parser.attribName = ""; - if (c === ">") openTag(parser); - else if (isMatch(nameStart, c)) { - parser.attribName = c; - parser.state = S.ATTRIB_NAME; - } else { - strictFail(parser, "Invalid attribute name"); - parser.state = S.ATTRIB; - } - } - continue; - case S.ATTRIB_VALUE: - if (isWhitespace(c)) continue; - else if (isQuote(c)) { - parser.q = c; - parser.state = S.ATTRIB_VALUE_QUOTED; - } else { - strictFail(parser, "Unquoted attribute value"); - parser.state = S.ATTRIB_VALUE_UNQUOTED; - parser.attribValue = c; - } - continue; - case S.ATTRIB_VALUE_QUOTED: - if (c !== parser.q) { - if (c === "&") parser.state = S.ATTRIB_VALUE_ENTITY_Q; - else parser.attribValue += c; - continue; - } - attrib(parser); - parser.q = ""; - parser.state = S.ATTRIB_VALUE_CLOSED; - continue; - case S.ATTRIB_VALUE_CLOSED: - if (isWhitespace(c)) parser.state = S.ATTRIB; - else if (c === ">") openTag(parser); - else if (c === "/") parser.state = S.OPEN_TAG_SLASH; - else if (isMatch(nameStart, c)) { - strictFail(parser, "No whitespace between attributes"); - parser.attribName = c; - parser.attribValue = ""; - parser.state = S.ATTRIB_NAME; - } else strictFail(parser, "Invalid attribute name"); - continue; - case S.ATTRIB_VALUE_UNQUOTED: - if (!isAttribEnd(c)) { - if (c === "&") parser.state = S.ATTRIB_VALUE_ENTITY_U; - else parser.attribValue += c; - continue; - } - attrib(parser); - if (c === ">") openTag(parser); - else parser.state = S.ATTRIB; - continue; - case S.CLOSE_TAG: - if (!parser.tagName) if (isWhitespace(c)) continue; - else if (notMatch(nameStart, c)) if (parser.script) { - parser.script += "") closeTag(parser); - else if (isMatch(nameBody, c)) parser.tagName += c; - else if (parser.script) { - parser.script += "") closeTag(parser); - else strictFail(parser, "Invalid characters in closing tag"); - continue; - case S.TEXT_ENTITY: - case S.ATTRIB_VALUE_ENTITY_Q: - case S.ATTRIB_VALUE_ENTITY_U: - var returnState; - var buffer; - switch (parser.state) { - case S.TEXT_ENTITY: - returnState = S.TEXT; - buffer = "textNode"; - break; - case S.ATTRIB_VALUE_ENTITY_Q: - returnState = S.ATTRIB_VALUE_QUOTED; - buffer = "attribValue"; - break; - case S.ATTRIB_VALUE_ENTITY_U: - returnState = S.ATTRIB_VALUE_UNQUOTED; - buffer = "attribValue"; - break; - } - if (c === ";") if (parser.opt.unparsedEntities) { - var parsedEntity = parseEntity(parser); - parser.entity = ""; - parser.state = returnState; - parser.write(parsedEntity); - } else { - parser[buffer] += parseEntity(parser); - parser.entity = ""; - parser.state = returnState; - } - else if (isMatch(parser.entity.length ? entityBody : entityStart, c)) parser.entity += c; - else { - strictFail(parser, "Invalid character in entity name"); - parser[buffer] += "&" + parser.entity + c; - parser.entity = ""; - parser.state = returnState; +}; +var FakeStreamingChatModel = class FakeStreamingChatModel extends BaseChatModel { + sleep = 50; + responses = []; + chunks = []; + toolStyle = "openai"; + thrownErrorString; + tools = []; + constructor({ sleep = 50, responses = [], chunks = [], toolStyle = "openai", thrownErrorString,...rest }) { + super(rest); + this.sleep = sleep; + this.responses = responses; + this.chunks = chunks; + this.toolStyle = toolStyle; + this.thrownErrorString = thrownErrorString; + } + _llmType() { + return "fake"; + } + bindTools(tools) { + const merged = [...this.tools, ...tools]; + const toolDicts = merged.map((t) => { + switch (this.toolStyle) { + case "openai": return { + type: "function", + function: { + name: t.name, + description: t.description, + parameters: toJsonSchema(t.schema) } - continue; - default: throw new Error(parser, "Unknown state: " + parser.state); + }; + case "anthropic": return { + name: t.name, + description: t.description, + input_schema: toJsonSchema(t.schema) + }; + case "bedrock": return { toolSpec: { + name: t.name, + description: t.description, + inputSchema: toJsonSchema(t.schema) + } }; + case "google": return { + name: t.name, + description: t.description, + parameters: toJsonSchema(t.schema) + }; + default: throw new Error(`Unsupported tool style: ${this.toolStyle}`); + } + }); + const wrapped = this.toolStyle === "google" ? [{ functionDeclarations: toolDicts }] : toolDicts; + const next = new FakeStreamingChatModel({ + sleep: this.sleep, + responses: this.responses, + chunks: this.chunks, + toolStyle: this.toolStyle, + thrownErrorString: this.thrownErrorString + }); + next.tools = merged; + return next.withConfig({ tools: wrapped }); + } + async _generate(messages, _options, _runManager) { + if (this.thrownErrorString) throw new Error(this.thrownErrorString); + const content = this.responses?.[0]?.content ?? messages[0].content ?? ""; + const generation = { generations: [{ + text: "", + message: new AIMessage({ + content, + tool_calls: this.chunks?.[0]?.tool_calls + }) + }] }; + return generation; + } + async *_streamResponseChunks(_messages, options, runManager) { + if (this.thrownErrorString) throw new Error(this.thrownErrorString); + if (this.chunks?.length) { + for (const msgChunk of this.chunks) { + const cg = new ChatGenerationChunk({ + message: new AIMessageChunk({ + content: msgChunk.content, + tool_calls: msgChunk.tool_calls, + additional_kwargs: msgChunk.additional_kwargs ?? {} + }), + text: msgChunk.content?.toString() ?? "" + }); + if (options.signal?.aborted) break; + yield cg; + await runManager?.handleLLMNewToken(msgChunk.content, void 0, void 0, void 0, void 0, { chunk: cg }); } + return; + } + const fallback = this.responses?.[0] ?? new AIMessage(typeof _messages[0].content === "string" ? _messages[0].content : ""); + const text = typeof fallback.content === "string" ? fallback.content : ""; + for (const ch of text) { + await new Promise((r) => setTimeout(r, this.sleep)); + const cg = new ChatGenerationChunk({ + message: new AIMessageChunk({ content: ch }), + text: ch + }); + if (options.signal?.aborted) break; + yield cg; + await runManager?.handleLLMNewToken(ch, void 0, void 0, void 0, void 0, { chunk: cg }); } - if (parser.position >= parser.bufferCheckPosition) checkBufferLength(parser); - return parser; } - /*! http://mths.be/fromcodepoint v0.1.0 by @mathias */ - /* istanbul ignore next */ - if (!String.fromCodePoint) (function() { - var stringFromCharCode = String.fromCharCode; - var floor = Math.floor; - var fromCodePoint = function() { - var MAX_SIZE = 16384; - var codeUnits = []; - var highSurrogate; - var lowSurrogate; - var index = -1; - var length = arguments.length; - if (!length) return ""; - var result = ""; - while (++index < length) { - var codePoint = Number(arguments[index]); - if (!isFinite(codePoint) || codePoint < 0 || codePoint > 1114111 || floor(codePoint) !== codePoint) throw RangeError("Invalid code point: " + codePoint); - if (codePoint <= 65535) codeUnits.push(codePoint); - else { - codePoint -= 65536; - highSurrogate = (codePoint >> 10) + 55296; - lowSurrogate = codePoint % 1024 + 56320; - codeUnits.push(highSurrogate, lowSurrogate); - } - if (index + 1 === length || codeUnits.length > MAX_SIZE) { - result += stringFromCharCode.apply(null, codeUnits); - codeUnits.length = 0; - } - } - return result; +}; +/** +* A fake Chat Model that returns a predefined list of responses. It can be used +* for testing purposes. +* @example +* ```typescript +* const chat = new FakeListChatModel({ +* responses: ["I'll callback later.", "You 'console' them!"] +* }); +* +* const firstMessage = new HumanMessage("You want to hear a JavaScript joke?"); +* const secondMessage = new HumanMessage("How do you cheer up a JavaScript developer?"); +* +* // Call the chat model with a message and log the response +* const firstResponse = await chat.call([firstMessage]); +* console.log({ firstResponse }); +* +* const secondResponse = await chat.call([secondMessage]); +* console.log({ secondResponse }); +* ``` +*/ +var FakeListChatModel = class FakeListChatModel extends BaseChatModel { + static lc_name() { + return "FakeListChatModel"; + } + lc_serializable = true; + responses; + i = 0; + sleep; + emitCustomEvent = false; + generationInfo; + tools = []; + toolStyle = "openai"; + constructor(params) { + super(params); + const { responses, sleep, emitCustomEvent, generationInfo } = params; + this.responses = responses; + this.sleep = sleep; + this.emitCustomEvent = emitCustomEvent ?? this.emitCustomEvent; + this.generationInfo = generationInfo; + } + _combineLLMOutput() { + return []; + } + _llmType() { + return "fake-list"; + } + async _generate(_messages, options, runManager) { + await this._sleepIfRequested(); + if (options?.thrownErrorString) throw new Error(options.thrownErrorString); + if (this.emitCustomEvent) await runManager?.handleCustomEvent("some_test_event", { someval: true }); + if (options?.stop?.length) return { generations: [this._formatGeneration(options.stop[0])] }; + else { + const response = this._currentResponse(); + this._incrementResponse(); + return { + generations: [this._formatGeneration(response)], + llmOutput: {} + }; + } + } + _formatGeneration(text) { + return { + message: new AIMessage(text), + text }; - /* istanbul ignore next */ - if (Object.defineProperty) Object.defineProperty(String, "fromCodePoint", { - value: fromCodePoint, - configurable: true, - writable: true + } + async *_streamResponseChunks(_messages, options, runManager) { + const response = this._currentResponse(); + this._incrementResponse(); + if (this.emitCustomEvent) await runManager?.handleCustomEvent("some_test_event", { someval: true }); + const responseChars = [...response]; + for (let i = 0; i < responseChars.length; i++) { + const text = responseChars[i]; + const isLastChunk = i === responseChars.length - 1; + await this._sleepIfRequested(); + if (options?.thrownErrorString) throw new Error(options.thrownErrorString); + const chunk = this._createResponseChunk(text, isLastChunk ? this.generationInfo : void 0); + if (options.signal?.aborted) break; + yield chunk; + runManager?.handleLLMNewToken(text); + } + } + async _sleepIfRequested() { + if (this.sleep !== void 0) await this._sleep(); + } + async _sleep() { + return new Promise((resolve) => { + setTimeout(() => resolve(), this.sleep); }); - else String.fromCodePoint = fromCodePoint; - })(); - return sax$1; + } + _createResponseChunk(text, generationInfo) { + return new ChatGenerationChunk({ + message: new AIMessageChunk({ content: text }), + text, + generationInfo + }); + } + _currentResponse() { + return this.responses[this.i]; + } + _incrementResponse() { + if (this.i < this.responses.length - 1) this.i += 1; + else this.i = 0; + } + bindTools(tools) { + const merged = [...this.tools, ...tools]; + const toolDicts = merged.map((t) => { + switch (this.toolStyle) { + case "openai": return { + type: "function", + function: { + name: t.name, + description: t.description, + parameters: toJsonSchema(t.schema) + } + }; + case "anthropic": return { + name: t.name, + description: t.description, + input_schema: toJsonSchema(t.schema) + }; + case "bedrock": return { toolSpec: { + name: t.name, + description: t.description, + inputSchema: toJsonSchema(t.schema) + } }; + case "google": return { + name: t.name, + description: t.description, + parameters: toJsonSchema(t.schema) + }; + default: throw new Error(`Unsupported tool style: ${this.toolStyle}`); + } + }); + const wrapped = this.toolStyle === "google" ? [{ functionDeclarations: toolDicts }] : toolDicts; + const next = new FakeListChatModel({ + responses: this.responses, + sleep: this.sleep, + emitCustomEvent: this.emitCustomEvent, + generationInfo: this.generationInfo + }); + next.tools = merged; + next.toolStyle = this.toolStyle; + next.i = this.i; + return next.withConfig({ tools: wrapped }); + } + withStructuredOutput(_params, _config) { + return RunnableLambda.from(async (input) => { + const message = await this.invoke(input); + if (message.tool_calls?.[0]?.args) return message.tool_calls[0].args; + if (typeof message.content === "string") return JSON.parse(message.content); + throw new Error("No structured output found"); + }); + } }; -const sax = initializeSax(); //#endregion -//# sourceMappingURL=sax.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/xml.js - +//# sourceMappingURL=chat_models.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/embeddings.js +//#region src/utils/testing/embeddings.ts +/** +* A class that provides synthetic embeddings by overriding the +* embedDocuments and embedQuery methods to generate embeddings based on +* the input documents. The embeddings are generated by converting each +* document into chunks, calculating a numerical value for each chunk, and +* returning an array of these values as the embedding. +*/ +var SyntheticEmbeddings = class extends Embeddings { + vectorSize; + constructor(params) { + super(params ?? {}); + this.vectorSize = params?.vectorSize ?? 4; + } + /** + * Generates synthetic embeddings for a list of documents. + * @param documents List of documents to generate embeddings for. + * @returns A promise that resolves with a list of synthetic embeddings for each document. + */ + async embedDocuments(documents) { + return Promise.all(documents.map((doc) => this.embedQuery(doc))); + } + /** + * Generates a synthetic embedding for a document. The document is + * converted into chunks, a numerical value is calculated for each chunk, + * and an array of these values is returned as the embedding. + * @param document The document to generate an embedding for. + * @returns A promise that resolves with a synthetic embedding for the document. + */ + async embedQuery(document) { + let doc = document; + doc = doc.toLowerCase().replaceAll(/[^a-z ]/g, ""); + const padMod = doc.length % this.vectorSize; + const padGapSize = padMod === 0 ? 0 : this.vectorSize - padMod; + const padSize = doc.length + padGapSize; + doc = doc.padEnd(padSize, " "); + const chunkSize = doc.length / this.vectorSize; + const docChunk = []; + for (let co = 0; co < doc.length; co += chunkSize) docChunk.push(doc.slice(co, co + chunkSize)); + const ret = docChunk.map((s) => { + let sum = 0; + for (let co = 0; co < s.length; co += 1) sum += s === " " ? 0 : s.charCodeAt(co); + const ret$1 = sum % 26 / 26; + return ret$1; + }); + return ret; + } +}; +/** +* A class that provides fake embeddings by overriding the embedDocuments +* and embedQuery methods to return fixed values. +*/ +var FakeEmbeddings = class extends Embeddings { + constructor(params) { + super(params ?? {}); + } + /** + * Generates fixed embeddings for a list of documents. + * @param documents List of documents to generate embeddings for. + * @returns A promise that resolves with a list of fixed embeddings for each document. + */ + embedDocuments(documents) { + return Promise.resolve(documents.map(() => [ + .1, + .2, + .3, + .4 + ])); + } + /** + * Generates a fixed embedding for a query. + * @param _ The query to generate an embedding for. + * @returns A promise that resolves with a fixed embedding for the query. + */ + embedQuery(_) { + return Promise.resolve([ + .1, + .2, + .3, + .4 + ]); + } +}; +//#endregion -//#region src/output_parsers/xml.ts -const XML_FORMAT_INSTRUCTIONS = `The output should be formatted as a XML file. -1. Output should conform to the tags below. -2. If tags are not given, make them on your own. -3. Remember to always open and close all the tags. +//# sourceMappingURL=embeddings.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/llms.js -As an example, for the tags ["foo", "bar", "baz"]: -1. String "\n \n \n \n" is a well-formatted instance of the schema. -2. String "\n \n " is a badly-formatted instance. -3. String "\n \n \n" is a badly-formatted instance. -Here are the output tags: -\`\`\` -{tags} -\`\`\``; -var XMLOutputParser = class extends BaseCumulativeTransformOutputParser { - tags; +//#region src/utils/testing/llms.ts +var FakeLLM = class extends LLM { + response; + thrownErrorString; constructor(fields) { super(fields); - this.tags = fields?.tags; + this.response = fields.response; + this.thrownErrorString = fields.thrownErrorString; } - static lc_name() { - return "XMLOutputParser"; + _llmType() { + return "fake"; } - lc_namespace = ["langchain_core", "output_parsers"]; - lc_serializable = true; - _diff(prev, next) { - if (!next) return void 0; - if (!prev) return [{ - op: "replace", - path: "", - value: next - }]; - return compare(prev, next); + async _call(prompt, _options, runManager) { + if (this.thrownErrorString) throw new Error(this.thrownErrorString); + const response = this.response ?? prompt; + await runManager?.handleLLMNewToken(response); + return response; } - async parsePartialResult(generations) { - return parseXMLMarkdown(generations[0].text); +}; +var FakeStreamingLLM = class extends LLM { + sleep = 50; + responses; + thrownErrorString; + constructor(fields) { + super(fields); + this.sleep = fields.sleep ?? this.sleep; + this.responses = fields.responses; + this.thrownErrorString = fields.thrownErrorString; } - async parse(text) { - return parseXMLMarkdown(text); + _llmType() { + return "fake"; } - getFormatInstructions() { - const withTags = !!(this.tags && this.tags.length > 0); - return withTags ? XML_FORMAT_INSTRUCTIONS.replace("{tags}", this.tags?.join(", ") ?? "") : XML_FORMAT_INSTRUCTIONS; + async _call(prompt) { + if (this.thrownErrorString) throw new Error(this.thrownErrorString); + const response = this.responses?.[0]; + this.responses = this.responses?.slice(1); + return response ?? prompt; + } + async *_streamResponseChunks(input, _options, runManager) { + if (this.thrownErrorString) throw new Error(this.thrownErrorString); + const response = this.responses?.[0]; + this.responses = this.responses?.slice(1); + for (const c of response ?? input) { + await new Promise((resolve) => setTimeout(resolve, this.sleep)); + yield { + text: c, + generationInfo: {} + }; + await runManager?.handleLLMNewToken(c); + } } }; -const strip = (text) => text.split("\n").map((line) => line.replace(/^\s+/, "")).join("\n").trim(); -const parseParsedResult = (input) => { - if (Object.keys(input).length === 0) return {}; - const result = {}; - if (input.children.length > 0) { - result[input.name] = input.children.map(parseParsedResult); - return result; - } else { - result[input.name] = input.text ?? void 0; - return result; + +//#endregion + +//# sourceMappingURL=llms.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/message_history.js + + + + + + +//#region src/utils/testing/message_history.ts +var FakeChatMessageHistory = class extends BaseChatMessageHistory { + lc_namespace = [ + "langchain_core", + "message", + "fake" + ]; + messages = []; + constructor() { + super(); + } + async getMessages() { + return this.messages; + } + async addMessage(message) { + this.messages.push(message); + } + async addUserMessage(message) { + this.messages.push(new HumanMessage(message)); + } + async addAIMessage(message) { + this.messages.push(new AIMessage(message)); + } + async clear() { + this.messages = []; + } +}; +var FakeListChatMessageHistory = class extends BaseListChatMessageHistory { + lc_namespace = [ + "langchain_core", + "message", + "fake" + ]; + messages = []; + constructor() { + super(); + } + async addMessage(message) { + this.messages.push(message); + } + async getMessages() { + return this.messages; + } +}; +var FakeTracer = class extends BaseTracer { + name = "fake_tracer"; + runs = []; + constructor() { + super(); + } + persistRun(run) { + this.runs.push(run); + return Promise.resolve(); + } +}; + +//#endregion + +//# sourceMappingURL=message_history.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/output_parsers.js + + +//#region src/utils/testing/output_parsers.ts +/** +* Parser for comma-separated values. It splits the input text by commas +* and trims the resulting values. +*/ +var FakeSplitIntoListParser = class extends BaseOutputParser { + lc_namespace = ["tests", "fake"]; + getFormatInstructions() { + return ""; + } + async parse(text) { + return text.split(",").map((value) => value.trim()); + } +}; + +//#endregion + +//# sourceMappingURL=output_parsers.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/retrievers.js + + + +//#region src/utils/testing/retrievers.ts +var FakeRetriever = class extends BaseRetriever { + lc_namespace = ["test", "fake"]; + output = [new Document({ pageContent: "foo" }), new Document({ pageContent: "bar" })]; + constructor(fields) { + super(); + this.output = fields?.output ?? this.output; + } + async _getRelevantDocuments(_query) { + return this.output; } }; -function parseXMLMarkdown(s) { - const cleanedString = strip(s); - const parser = sax.parser(true); - let parsedResult = {}; - const elementStack = []; - parser.onopentag = (node) => { - const element = { - name: node.name, - attributes: node.attributes, - children: [], - text: "", - isSelfClosing: node.isSelfClosing - }; - if (elementStack.length > 0) { - const parentElement = elementStack[elementStack.length - 1]; - parentElement.children.push(element); - } else parsedResult = element; - if (!node.isSelfClosing) elementStack.push(element); - }; - parser.onclosetag = () => { - if (elementStack.length > 0) { - const lastElement = elementStack.pop(); - if (elementStack.length === 0 && lastElement) parsedResult = lastElement; - } - }; - parser.ontext = (text) => { - if (elementStack.length > 0) { - const currentElement = elementStack[elementStack.length - 1]; - currentElement.text += text; - } - }; - parser.onattribute = (attr) => { - if (elementStack.length > 0) { - const currentElement = elementStack[elementStack.length - 1]; - currentElement.attributes[attr.name] = attr.value; - } - }; - const match = /```(xml)?(.*)```/s.exec(cleanedString); - const xmlString = match ? match[2] : cleanedString; - parser.write(xmlString).close(); - if (parsedResult && parsedResult.name === "?xml") parsedResult = parsedResult.children[0]; - return parseParsedResult(parsedResult); -} //#endregion -//# sourceMappingURL=xml.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/output_parsers/index.js - +//# sourceMappingURL=retrievers.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/runnables.js +//#region src/utils/testing/runnables.ts +var FakeRunnable = class extends Runnable { + lc_namespace = ["tests", "fake"]; + returnOptions; + constructor(fields) { + super(fields); + this.returnOptions = fields.returnOptions; + } + async invoke(input, options) { + if (this.returnOptions) return options ?? {}; + return { input }; + } +}; +//#endregion +//# sourceMappingURL=runnables.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/tools.js +//#region src/utils/testing/tools.ts +var FakeTool = class extends StructuredTool { + name; + description; + schema; + constructor(fields) { + super(fields); + this.name = fields.name; + this.description = fields.description; + this.schema = fields.schema; + } + async _call(arg, _runManager) { + return JSON.stringify(arg); + } +}; +//#endregion +//# sourceMappingURL=tools.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/tracers.js -//#region src/output_parsers/index.ts -var output_parsers_exports = {}; -__export(output_parsers_exports, { - AsymmetricStructuredOutputParser: () => AsymmetricStructuredOutputParser, - BaseCumulativeTransformOutputParser: () => BaseCumulativeTransformOutputParser, - BaseLLMOutputParser: () => BaseLLMOutputParser, - BaseOutputParser: () => BaseOutputParser, - BaseTransformOutputParser: () => BaseTransformOutputParser, - BytesOutputParser: () => BytesOutputParser, - CommaSeparatedListOutputParser: () => CommaSeparatedListOutputParser, - CustomListOutputParser: () => CustomListOutputParser, - JsonMarkdownStructuredOutputParser: () => JsonMarkdownStructuredOutputParser, - JsonOutputParser: () => JsonOutputParser, - ListOutputParser: () => ListOutputParser, - MarkdownListOutputParser: () => MarkdownListOutputParser, - NumberedListOutputParser: () => NumberedListOutputParser, - OutputParserException: () => OutputParserException, - StringOutputParser: () => StringOutputParser, - StructuredOutputParser: () => StructuredOutputParser, - XMLOutputParser: () => XMLOutputParser, - XML_FORMAT_INSTRUCTIONS: () => XML_FORMAT_INSTRUCTIONS, - parseJsonMarkdown: () => parseJsonMarkdown, - parsePartialJson: () => parsePartialJson, - parseXMLMarkdown: () => parseXMLMarkdown -}); +//#region src/utils/testing/tracers.ts +var SingleRunExtractor = class extends BaseTracer { + runPromiseResolver; + runPromise; + /** The name of the callback handler. */ + name = "single_run_extractor"; + constructor() { + super(); + this.runPromise = new Promise((extract) => { + this.runPromiseResolver = extract; + }); + } + async persistRun(run) { + this.runPromiseResolver(run); + } + async extract() { + return this.runPromise; + } +}; //#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/format.js -//#region src/utils/format.ts -var format_exports = {}; +//# sourceMappingURL=tracers.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/vectorstores.js -//#endregion -//# sourceMappingURL=format.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/ml-distance/distances.js -//#region src/utils/ml-distance/distances.ts + + +//#region src/utils/testing/vectorstores.ts /** -*Returns the Inner Product similarity between vectors a and b -* @link [Inner Product Similarity algorithm](https://www.naun.org/main/NAUN/ijmmas/mmmas-49.pdf) -* @param a - first vector -* @param b - second vector -* +* Class that extends `VectorStore` to store vectors in memory. Provides +* methods for adding documents, performing similarity searches, and +* creating instances from texts, documents, or an existing index. */ -function innerProduct(a, b) { - let ans = 0; - for (let i = 0; i < a.length; i++) ans += a[i] * b[i]; - return ans; -} +var FakeVectorStore = class FakeVectorStore extends VectorStore { + memoryVectors = []; + similarity; + _vectorstoreType() { + return "memory"; + } + constructor(embeddings, { similarity,...rest } = {}) { + super(embeddings, rest); + this.similarity = similarity ?? cosine; + } + /** + * Method to add documents to the memory vector store. It extracts the + * text from each document, generates embeddings for them, and adds the + * resulting vectors to the store. + * @param documents Array of `Document` instances to be added to the store. + * @returns Promise that resolves when all documents have been added. + */ + async addDocuments(documents) { + const texts = documents.map(({ pageContent }) => pageContent); + return this.addVectors(await this.embeddings.embedDocuments(texts), documents); + } + /** + * Method to add vectors to the memory vector store. It creates + * `MemoryVector` instances for each vector and document pair and adds + * them to the store. + * @param vectors Array of vectors to be added to the store. + * @param documents Array of `Document` instances corresponding to the vectors. + * @returns Promise that resolves when all vectors have been added. + */ + async addVectors(vectors, documents) { + const memoryVectors = vectors.map((embedding, idx) => ({ + content: documents[idx].pageContent, + embedding, + metadata: documents[idx].metadata + })); + this.memoryVectors = this.memoryVectors.concat(memoryVectors); + } + /** + * Method to perform a similarity search in the memory vector store. It + * calculates the similarity between the query vector and each vector in + * the store, sorts the results by similarity, and returns the top `k` + * results along with their scores. + * @param query Query vector to compare against the vectors in the store. + * @param k Number of top results to return. + * @param filter Optional filter function to apply to the vectors before performing the search. + * @returns Promise that resolves with an array of tuples, each containing a `Document` and its similarity score. + */ + async similaritySearchVectorWithScore(query, k, filter) { + const filterFunction = (memoryVector) => { + if (!filter) return true; + const doc = new Document({ + metadata: memoryVector.metadata, + pageContent: memoryVector.content + }); + return filter(doc); + }; + const filteredMemoryVectors = this.memoryVectors.filter(filterFunction); + const searches = filteredMemoryVectors.map((vector, index) => ({ + similarity: this.similarity(query, vector.embedding), + index + })).sort((a, b) => a.similarity > b.similarity ? -1 : 0).slice(0, k); + const result = searches.map((search) => [new Document({ + metadata: filteredMemoryVectors[search.index].metadata, + pageContent: filteredMemoryVectors[search.index].content + }), search.similarity]); + return result; + } + /** + * Static method to create a `FakeVectorStore` instance from an array of + * texts. It creates a `Document` for each text and metadata pair, and + * adds them to the store. + * @param texts Array of texts to be added to the store. + * @param metadatas Array or single object of metadata corresponding to the texts. + * @param embeddings `Embeddings` instance used to generate embeddings for the texts. + * @param dbConfig Optional `FakeVectorStoreArgs` to configure the `FakeVectorStore` instance. + * @returns Promise that resolves with a new `FakeVectorStore` instance. + */ + static async fromTexts(texts, metadatas, embeddings, dbConfig) { + const docs = []; + for (let i = 0; i < texts.length; i += 1) { + const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas; + const newDoc = new Document({ + pageContent: texts[i], + metadata + }); + docs.push(newDoc); + } + return FakeVectorStore.fromDocuments(docs, embeddings, dbConfig); + } + /** + * Static method to create a `FakeVectorStore` instance from an array of + * `Document` instances. It adds the documents to the store. + * @param docs Array of `Document` instances to be added to the store. + * @param embeddings `Embeddings` instance used to generate embeddings for the documents. + * @param dbConfig Optional `FakeVectorStoreArgs` to configure the `FakeVectorStore` instance. + * @returns Promise that resolves with a new `FakeVectorStore` instance. + */ + static async fromDocuments(docs, embeddings, dbConfig) { + const instance = new this(embeddings, dbConfig); + await instance.addDocuments(docs); + return instance; + } + /** + * Static method to create a `FakeVectorStore` instance from an existing + * index. It creates a new `FakeVectorStore` instance without adding any + * documents or vectors. + * @param embeddings `Embeddings` instance used to generate embeddings for the documents. + * @param dbConfig Optional `FakeVectorStoreArgs` to configure the `FakeVectorStore` instance. + * @returns Promise that resolves with a new `FakeVectorStore` instance. + */ + static async fromExistingIndex(embeddings, dbConfig) { + const instance = new this(embeddings, dbConfig); + return instance; + } +}; //#endregion -//# sourceMappingURL=distances.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/ml-distance-euclidean/euclidean.js -//#region src/utils/ml-distance-euclidean/euclidean.ts -function squaredEuclidean(p, q) { - let d = 0; - for (let i = 0; i < p.length; i++) d += (p[i] - q[i]) * (p[i] - q[i]); - return d; -} -function euclidean(p, q) { - return Math.sqrt(squaredEuclidean(p, q)); -} +//# sourceMappingURL=vectorstores.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/testing/index.js -//#endregion -//# sourceMappingURL=euclidean.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/math.js -//#region src/utils/math.ts -var math_exports = {}; -__export(math_exports, { - cosineSimilarity: () => cosineSimilarity, - euclideanDistance: () => euclideanDistance, - innerProduct: () => innerProduct$1, - matrixFunc: () => matrixFunc, - maximalMarginalRelevance: () => maximalMarginalRelevance, - normalize: () => normalize + + + + + +//#region src/utils/testing/index.ts +var testing_exports = {}; +__export(testing_exports, { + FakeChatMessageHistory: () => FakeChatMessageHistory, + FakeChatModel: () => FakeChatModel, + FakeEmbeddings: () => FakeEmbeddings, + FakeLLM: () => FakeLLM, + FakeListChatMessageHistory: () => FakeListChatMessageHistory, + FakeListChatModel: () => FakeListChatModel, + FakeRetriever: () => FakeRetriever, + FakeRunnable: () => FakeRunnable, + FakeSplitIntoListParser: () => FakeSplitIntoListParser, + FakeStreamingChatModel: () => FakeStreamingChatModel, + FakeStreamingLLM: () => FakeStreamingLLM, + FakeTool: () => FakeTool, + FakeTracer: () => FakeTracer, + FakeVectorStore: () => FakeVectorStore, + SingleRunExtractor: () => SingleRunExtractor, + SyntheticEmbeddings: () => SyntheticEmbeddings }); -/** -* Apply a row-wise function between two matrices with the same number of columns. -* -* @param {number[][]} X - The first matrix. -* @param {number[][]} Y - The second matrix. -* @param {VectorFunction} func - The function to apply. -* -* @throws {Error} If the number of columns in X and Y are not the same. -* -* @returns {number[][] | [[]]} A matrix where each row represents the result of applying the function between the corresponding rows of X and Y. -*/ -function matrixFunc(X, Y, func) { - if (X.length === 0 || X[0].length === 0 || Y.length === 0 || Y[0].length === 0) return [[]]; - if (X[0].length !== Y[0].length) throw new Error(`Number of columns in X and Y must be the same. X has shape ${[X.length, X[0].length]} and Y has shape ${[Y.length, Y[0].length]}.`); - return X.map((xVector) => Y.map((yVector) => func(xVector, yVector)).map((similarity) => Number.isNaN(similarity) ? 0 : similarity)); -} -function normalize(M, similarity = false) { - const max = matrixMaxVal(M); - return M.map((row) => row.map((val) => similarity ? 1 - val / max : val / max)); -} -/** -* This function calculates the row-wise cosine similarity between two matrices with the same number of columns. -* -* @param {number[][]} X - The first matrix. -* @param {number[][]} Y - The second matrix. -* -* @throws {Error} If the number of columns in X and Y are not the same. -* -* @returns {number[][] | [[]]} A matrix where each row represents the cosine similarity values between the corresponding rows of X and Y. -*/ -function cosineSimilarity(X, Y) { - return matrixFunc(X, Y, cosine); -} -function innerProduct$1(X, Y) { - return matrixFunc(X, Y, innerProduct); -} -function euclideanDistance(X, Y) { - return matrixFunc(X, Y, euclidean); -} -/** -* This function implements the Maximal Marginal Relevance algorithm -* to select a set of embeddings that maximizes the diversity and relevance to a query embedding. -* -* @param {number[]|number[][]} queryEmbedding - The query embedding. -* @param {number[][]} embeddingList - The list of embeddings to select from. -* @param {number} [lambda=0.5] - The trade-off parameter between relevance and diversity. -* @param {number} [k=4] - The maximum number of embeddings to select. -* -* @returns {number[]} The indexes of the selected embeddings in the embeddingList. -*/ -function maximalMarginalRelevance(queryEmbedding, embeddingList, lambda = .5, k = 4) { - if (Math.min(k, embeddingList.length) <= 0) return []; - const queryEmbeddingExpanded = Array.isArray(queryEmbedding[0]) ? queryEmbedding : [queryEmbedding]; - const similarityToQuery = cosineSimilarity(queryEmbeddingExpanded, embeddingList)[0]; - const mostSimilarEmbeddingIndex = argMax(similarityToQuery).maxIndex; - const selectedEmbeddings = [embeddingList[mostSimilarEmbeddingIndex]]; - const selectedEmbeddingsIndexes = [mostSimilarEmbeddingIndex]; - while (selectedEmbeddingsIndexes.length < Math.min(k, embeddingList.length)) { - let bestScore = -Infinity; - let bestIndex = -1; - const similarityToSelected = cosineSimilarity(embeddingList, selectedEmbeddings); - similarityToQuery.forEach((queryScore, queryScoreIndex) => { - if (selectedEmbeddingsIndexes.includes(queryScoreIndex)) return; - const maxSimilarityToSelected = Math.max(...similarityToSelected[queryScoreIndex]); - const score = lambda * queryScore - (1 - lambda) * maxSimilarityToSelected; - if (score > bestScore) { - bestScore = score; - bestIndex = queryScoreIndex; - } - }); - selectedEmbeddings.push(embeddingList[bestIndex]); - selectedEmbeddingsIndexes.push(bestIndex); - } - return selectedEmbeddingsIndexes; -} -/** -* Finds the index of the maximum value in the given array. -* @param {number[]} array - The input array. -* -* @returns {number} The index of the maximum value in the array. If the array is empty, returns -1. -*/ -function argMax(array) { - if (array.length === 0) return { - maxIndex: -1, - maxValue: NaN - }; - let maxValue = array[0]; - let maxIndex = 0; - for (let i = 1; i < array.length; i += 1) if (array[i] > maxValue) { - maxIndex = i; - maxValue = array[i]; - } - return { - maxIndex, - maxValue - }; -} -function matrixMaxVal(arrays) { - return arrays.reduce((acc, array) => Math.max(acc, argMax(array).maxValue), 0); -} //#endregion -//# sourceMappingURL=math.js.map +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/utils/types/index.js + + + +//#region src/utils/types/index.ts +var types_exports = {}; +__export(types_exports, { + extendInteropZodObject: () => extendInteropZodObject, + getInteropZodDefaultGetter: () => getInteropZodDefaultGetter, + getInteropZodObjectShape: () => getInteropZodObjectShape, + getSchemaDescription: () => getSchemaDescription, + interopParse: () => interopParse, + interopParseAsync: () => interopParseAsync, + interopSafeParse: () => interopSafeParse, + interopSafeParseAsync: () => interopSafeParseAsync, + interopZodObjectMakeFieldsOptional: () => interopZodObjectMakeFieldsOptional, + interopZodObjectPartial: () => interopZodObjectPartial, + interopZodObjectPassthrough: () => interopZodObjectPassthrough, + interopZodObjectStrict: () => interopZodObjectStrict, + interopZodTransformInputSchema: () => interopZodTransformInputSchema, + isInteropZodError: () => isInteropZodError, + isInteropZodLiteral: () => isInteropZodLiteral, + isInteropZodObject: () => isInteropZodObject, + isInteropZodSchema: () => isInteropZodSchema, + isShapelessZodSchema: () => isShapelessZodSchema, + isSimpleStringZodSchema: () => isSimpleStringZodSchema, + isZodArrayV4: () => isZodArrayV4, + isZodLiteralV3: () => isZodLiteralV3, + isZodLiteralV4: () => isZodLiteralV4, + isZodNullableV4: () => isZodNullableV4, + isZodObjectV3: () => isZodObjectV3, + isZodObjectV4: () => isZodObjectV4, + isZodOptionalV4: () => isZodOptionalV4, + isZodSchema: () => isZodSchema, + isZodSchemaV3: () => isZodSchemaV3, + isZodSchemaV4: () => isZodSchemaV4 +}); + +//#endregion + +//# sourceMappingURL=index.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/core/dist/load/import_map.js @@ -84729,6 +78039,7 @@ function matrixMaxVal(arrays) { + //#region src/load/import_map.ts @@ -84777,6 +78088,7 @@ __export(import_map_exports, { types__stream: () => stream_stream_exports, utils__async_caller: () => async_caller_exports, utils__chunk_array: () => chunk_array_exports, + utils__context: () => context_exports, utils__env: () => env_exports, utils__event_source_parse: () => event_source_parse_exports, utils__format: () => format_exports, @@ -84802,7 +78114,13 @@ __export(import_map_exports, { + //#region src/load/index.ts +/** +* Default maximum recursion depth for deserialization. +* This provides protection against DoS attacks via deeply nested structures. +*/ +const DEFAULT_MAX_DEPTH = 50; function combineAliasesAndInvert(constructor) { const aliases = {}; for (let current = constructor; current && current.prototype; current = Object.getPrototypeOf(current)) Object.assign(aliases, Reflect.get(current.prototype, "lc_aliases")); @@ -84811,24 +78129,44 @@ function combineAliasesAndInvert(constructor) { return acc; }, {}); } +/** +* Recursively revive a value, handling escape markers and LC objects. +* +* This function handles: +* 1. Escaped dicts - unwrapped and returned as plain objects +* 2. LC secret objects - resolved from secretsMap or env +* 3. LC constructor objects - instantiated +* 4. Regular objects/arrays - recursed into +*/ async function reviver(value) { - const { optionalImportsMap = {}, optionalImportEntrypoints: optionalImportEntrypoints$1 = [], importMap = {}, secretsMap = {}, path = ["$"] } = this; + const { optionalImportsMap, optionalImportEntrypoints: optionalImportEntrypoints$1, importMap, secretsMap, secretsFromEnv, path, depth, maxDepth } = this; const pathStr = path.join("."); - if (typeof value === "object" && value !== null && !Array.isArray(value) && "lc" in value && "type" in value && "id" in value && value.lc === 1 && value.type === "secret") { - const serialized = value; + if (depth > maxDepth) throw new Error(`Maximum recursion depth (${maxDepth}) exceeded during deserialization. This may indicate a malicious payload or you may need to increase maxDepth.`); + if (typeof value !== "object" || value == null) return value; + if (Array.isArray(value)) return Promise.all(value.map((v, i) => reviver.call({ + ...this, + path: [...path, `${i}`], + depth: depth + 1 + }, v))); + const record = value; + if (isEscapedObject(record)) return unescapeValue(record); + if ("lc" in record && "type" in record && "id" in record && record.lc === 1 && record.type === "secret") { + const serialized = record; const [key] = serialized.id; if (key in secretsMap) return secretsMap[key]; - else { + else if (secretsFromEnv) { const secretValueInEnv = getEnvironmentVariable(key); if (secretValueInEnv) return secretValueInEnv; - else throw new Error(`Missing key "${key}" for ${pathStr} in load(secretsMap={})`); } - } else if (typeof value === "object" && value !== null && !Array.isArray(value) && "lc" in value && "type" in value && "id" in value && value.lc === 1 && value.type === "not_implemented") { - const serialized = value; + throw new Error(`Missing secret "${key}" at ${pathStr}`); + } + if ("lc" in record && "type" in record && "id" in record && record.lc === 1 && record.type === "not_implemented") { + const serialized = record; const str = JSON.stringify(serialized); throw new Error(`Trying to load an object that doesn't implement serialization: ${pathStr} -> ${str}`); - } else if (typeof value === "object" && value !== null && !Array.isArray(value) && "lc" in value && "type" in value && "id" in value && "kwargs" in value && value.lc === 1) { - const serialized = value; + } + if ("lc" in record && "type" in record && "id" in record && "kwargs" in record && record.lc === 1 && record.type === "constructor") { + const serialized = record; const str = JSON.stringify(serialized); const [name, ...namespaceReverse] = serialized.id.slice().reverse(); const namespace = namespaceReverse.reverse(); @@ -84862,26 +78200,60 @@ async function reviver(value) { if (typeof builder !== "function") throw new Error(`Invalid identifer: ${pathStr} -> ${str}`); const kwargs = await reviver.call({ ...this, - path: [...path, "kwargs"] + path: [...path, "kwargs"], + depth: depth + 1 }, serialized.kwargs); - if (serialized.type === "constructor") { - const instance = new builder(mapKeys(kwargs, keyFromJson, combineAliasesAndInvert(builder))); - Object.defineProperty(instance.constructor, "name", { value: name }); - return instance; - } else throw new Error(`Invalid type: ${pathStr} -> ${str}`); - } else if (typeof value === "object" && value !== null) if (Array.isArray(value)) return Promise.all(value.map((v, i) => reviver.call({ - ...this, - path: [...path, `${i}`] - }, v))); - else return Object.fromEntries(await Promise.all(Object.entries(value).map(async ([key, value$1]) => [key, await reviver.call({ + const instance = new builder(mapKeys(kwargs, keyFromJson, combineAliasesAndInvert(builder))); + Object.defineProperty(instance.constructor, "name", { value: name }); + return instance; + } + const result = {}; + for (const [key, val] of Object.entries(record)) result[key] = await reviver.call({ ...this, - path: [...path, key] - }, value$1)]))); - return value; + path: [...path, key], + depth: depth + 1 + }, val); + return result; } -async function load(text, mappings) { +/** +* Load a LangChain object from a JSON string. +* +* @param text - The JSON string to parse and load. +* @param options - Options for loading. +* @returns The loaded LangChain object. +* +* @example +* ```typescript +* import { load } from "@langchain/core/load"; +* import { AIMessage } from "@langchain/core/messages"; +* +* // Basic usage - secrets must be provided explicitly +* const msg = await load(jsonString); +* +* // With secrets from a map +* const msg = await load(jsonString, { +* secretsMap: { OPENAI_API_KEY: "sk-..." } +* }); +* +* // Allow loading secrets from environment (use with caution) +* const msg = await load(jsonString, { +* secretsFromEnv: true +* }); +* ``` +*/ +async function load(text, options) { const json = JSON.parse(text); - return reviver.call({ ...mappings }, json); + const context = { + optionalImportsMap: options?.optionalImportsMap ?? {}, + optionalImportEntrypoints: options?.optionalImportEntrypoints ?? [], + secretsMap: options?.secretsMap ?? {}, + secretsFromEnv: options?.secretsFromEnv ?? false, + importMap: options?.importMap ?? {}, + path: ["$"], + depth: 0, + maxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH + }; + return reviver.call(context, json); } //#endregion @@ -86274,8 +79646,13 @@ var BinaryOperatorAggregate = class BinaryOperatorAggregate extends BaseChannel var LastValue = class LastValue extends BaseChannel { lc_graph_name = "LastValue"; value = []; + constructor(initialValueFactory) { + super(); + this.initialValueFactory = initialValueFactory; + if (initialValueFactory) this.value = [initialValueFactory()]; + } fromCheckpoint(checkpoint) { - const empty = new LastValue(); + const empty = new LastValue(this.initialValueFactory); if (typeof checkpoint !== "undefined") empty.value = [checkpoint]; return empty; } @@ -86944,7 +80321,7 @@ const PRIME64_4 = n("0x85EBCA77C2B2AE63"); const PRIME64_5 = n("0x27D4EB2F165667C5"); const PRIME_MX1 = n("0x165667919E3779F9"); const PRIME_MX2 = n("0x9FB21C651E98DF25"); -const hash_hexToUint8Array = (hex) => { +const hexToUint8Array = (hex) => { const strLen = hex.length; if (strLen % 2 !== 0) throw new Error("String should have an even number of characters"); const maxLength = strLen / 2; @@ -86958,7 +80335,7 @@ const hash_hexToUint8Array = (hex) => { } return view(bytes); }; -const kkey = hash_hexToUint8Array("b8fe6c3923a44bbe7c01812cf721ad1cded46de9839097db7240a4a4b7b3671fcb79e64eccc0e578825ad07dccff7221b8084674f743248ee03590e6813a264c3c2852bb91c300cb88d0658b1b532ea371644897a20df94e3819ef46a9deacd8a8fa763fe39c343ff9dcbbc7c70b4f1d8a51e04bcdb45931c89f7ec9d9787364eac5ac8334d3ebc3c581a0fffa1363eb170ddd51b7f0da49d316552629d4689e2b16be587d47a1fc8ff8b8d17ad031ce45cb3a8f95160428afd7fbcabb4b407e"); +const kkey = hexToUint8Array("b8fe6c3923a44bbe7c01812cf721ad1cded46de9839097db7240a4a4b7b3671fcb79e64eccc0e578825ad07dccff7221b8084674f743248ee03590e6813a264c3c2852bb91c300cb88d0658b1b532ea371644897a20df94e3819ef46a9deacd8a8fa763fe39c343ff9dcbbc7c70b4f1d8a51e04bcdb45931c89f7ec9d9787364eac5ac8334d3ebc3c581a0fffa1363eb170ddd51b7f0da49d316552629d4689e2b16be587d47a1fc8ff8b8d17ad031ce45cb3a8f95160428afd7fbcabb4b407e"); const mask128 = (n(1) << n(128)) - n(1); const mask64 = (n(1) << n(64)) - n(1); const mask32 = (n(1) << n(32)) - n(1); @@ -87053,8 +80430,7 @@ function XXH3_hashLong_128b(data, secret) { hash_assert(acc.length * 8 === 64); { const low64 = XXH3_mergeAccs(acc, view(secret, 11), n(data.byteLength) * PRIME64_1 & mask64); - const high64 = XXH3_mergeAccs(acc, view(secret, secret.byteLength - STRIPE_LEN - 11), ~(n(data.byteLength) * PRIME64_2) & mask64); - return high64 << n(64) | low64; + return XXH3_mergeAccs(acc, view(secret, secret.byteLength - STRIPE_LEN - 11), ~(n(data.byteLength) * PRIME64_2) & mask64) << n(64) | low64; } } function XXH3_mul128_fold64(a, b) { @@ -87098,11 +80474,9 @@ function XXH3_len_1to3_128b(data, key32, seed) { const len = data.byteLength; hash_assert(len > 0 && len <= 3); const combined = n(data.getUint8(len - 1)) | n(len << 8) | n(data.getUint8(0) << 16) | n(data.getUint8(len >> 1) << 24); - const blow = (n(key32.getUint32(0, true)) ^ n(key32.getUint32(4, true))) + seed; - const low = (combined ^ blow) & mask64; + const low = (combined ^ (n(key32.getUint32(0, true)) ^ n(key32.getUint32(4, true))) + seed) & mask64; const bhigh = (n(key32.getUint32(8, true)) ^ n(key32.getUint32(12, true))) - seed; - const high = (rotl32(bswap32(combined), n(13)) ^ bhigh) & mask64; - return (XXH3_avalanche64(high) & mask64) << n(64) | XXH3_avalanche64(low); + return (XXH3_avalanche64((rotl32(bswap32(combined), n(13)) ^ bhigh) & mask64) & mask64) << n(64) | XXH3_avalanche64(low); } function xorshift64(b, shift) { return b ^ b >> shift; @@ -87113,10 +80487,7 @@ function XXH3_len_4to8_128b(data, key32, seed) { { const l1 = data.getUint32(0, true); const l2 = data.getUint32(len - 4, true); - const l64 = n(l1) | n(l2) << n(32); - const bitflip = (key32.getBigUint64(16, true) ^ key32.getBigUint64(24, true)) + seed & mask64; - const keyed = l64 ^ bitflip; - let m128 = keyed * (PRIME64_1 + (n(len) << n(2))) & mask128; + let m128 = ((n(l1) | n(l2) << n(32)) ^ (key32.getBigUint64(16, true) ^ key32.getBigUint64(24, true)) + seed & mask64) * (PRIME64_1 + (n(len) << n(2))) & mask128; m128 += (m128 & mask64) << n(65); m128 &= mask128; m128 ^= m128 >> n(67); @@ -87255,8 +80626,7 @@ function interrupt(value) { if (!config) throw new Error("Called interrupt() outside the context of a graph."); const conf = config.configurable; if (!conf) throw new Error("No configurable found in config"); - const checkpointer = conf[CONFIG_KEY_CHECKPOINTER]; - if (!checkpointer) throw new GraphValueError("No checkpointer set", { lc_error_code: "MISSING_CHECKPOINTER" }); + if (!conf[CONFIG_KEY_CHECKPOINTER]) throw new GraphValueError("No checkpointer set", { lc_error_code: "MISSING_CHECKPOINTER" }); const scratchpad = conf[constants_CONFIG_KEY_SCRATCHPAD]; scratchpad.interruptCounter += 1; const idx = scratchpad.interruptCounter; @@ -87272,9 +80642,8 @@ function interrupt(value) { return v; } const ns = conf[CONFIG_KEY_CHECKPOINT_NS]?.split(CHECKPOINT_NAMESPACE_SEPARATOR); - const id = ns ? XXH3(ns.join(CHECKPOINT_NAMESPACE_SEPARATOR)) : void 0; throw new GraphInterrupt([{ - id, + id: ns ? XXH3(ns.join(CHECKPOINT_NAMESPACE_SEPARATOR)) : void 0, value }]); } @@ -87308,8 +80677,7 @@ var RunnableCallable = class extends Runnable { const childConfig = config_patchConfig(config, { callbacks: runManager?.getChild() }); async_local_storage_AsyncLocalStorageProviderSingleton.runWithConfig(childConfig, async () => { try { - const output = await this.func(input, childConfig); - resolve(output); + resolve(await this.func(input, childConfig)); } catch (e) { reject(e); } @@ -87537,7 +80905,7 @@ var PregelNode = class PregelNode extends RunnableBinding { } getNode() { const writers = this.getWriters(); - if (this.bound === defaultRunnableBound && writers.length === 0) return void 0; + if (this.bound === defaultRunnableBound && writers.length === 0) return; else if (this.bound === defaultRunnableBound && writers.length === 1) return writers[0]; else if (this.bound === defaultRunnableBound) return new RunnableSequence({ first: writers[0], @@ -87623,7 +80991,6 @@ function findSubgraphPregel(candidate) { const candidates = [candidate]; for (const candidate$1 of candidates) if (isPregelLike(candidate$1)) return candidate$1; else if (isRunnableSequence(candidate$1)) candidates.push(...candidate$1.steps); - return void 0; } //#endregion @@ -87780,7 +81147,6 @@ function getNullChannelVersion(currentVersions) { if (versionType === "string") return ""; break; } - return void 0; } function getNewChannelVersions(previousVersions, currentVersions) { if (Object.keys(previousVersions).length > 0) { @@ -87851,7 +81217,7 @@ function combineAbortSignals(...x) { * @returns A single callback that is a combination of the input callbacks. */ const combineCallbacks = (callback1, callback2) => { - if (!callback1 && !callback2) return void 0; + if (!callback1 && !callback2) return; if (!callback1) return callback2; if (!callback2) return callback1; if (Array.isArray(callback1) && Array.isArray(callback2)) return [...callback1, ...callback2]; @@ -87901,15 +81267,14 @@ function isCall(value) { * Wraps a user function in a Runnable that writes the returned value to the RETURN channel. */ function getRunnableForFunc(name, func) { - const run = new RunnableCallable({ - func: (input) => func(...input), - name, - trace: false, - recurse: false - }); return new RunnableSequence({ name, - first: run, + first: new RunnableCallable({ + func: (input) => func(...input), + name, + trace: false, + recurse: false + }), last: new ChannelWrite([{ channel: RETURN, value: PASSTHROUGH @@ -87917,7 +81282,7 @@ function getRunnableForFunc(name, func) { }); } function getRunnableForEntrypoint(name, func) { - const run = new RunnableCallable({ + return new RunnableCallable({ func: (input, config) => { return func(input, config); }, @@ -87925,7 +81290,6 @@ function getRunnableForEntrypoint(name, func) { trace: false, recurse: false }); - return run; } function call_call({ func, name, cache, retry }, ...args) { const config = AsyncLocalStorageProviderSingleton.getRunnableConfig(); @@ -88075,8 +81439,7 @@ function _applyWrites(checkpoint, channels, tasks, getNextVersion, triggerToNode if (!Object.prototype.hasOwnProperty.call(onlyChannels, chan)) continue; const channel = onlyChannels[chan]; if (channel.isAvailable() && !updatedChannels.has(chan)) { - const updated = channel.update([]); - if (updated && getNextVersion !== void 0) { + if (channel.update([]) && getNextVersion !== void 0) { checkpoint.channel_versions[chan] = getNextVersion(maxVersion); if (channel.isAvailable()) updatedChannels.add(chan); } @@ -88102,11 +81465,10 @@ function* candidateNodes(checkpoint, processes, extra) { yield* [...triggeredNodes].sort(); return; } - const isEmptyChannelVersions = (() => { + if ((() => { for (const chan in checkpoint.channel_versions) if (checkpoint.channel_versions[chan] !== null) return false; return true; - })(); - if (isEmptyChannelVersions) return; + })()) return; for (const name in processes) { if (!Object.prototype.hasOwnProperty.call(processes, name)) continue; yield name; @@ -88165,7 +81527,7 @@ function _prepareSingleTask(taskPath, checkpoint, pendingWrites, processes, chan }; if (forExecution) { const writes = []; - const task = { + return { name: call.name, input: call.input, proc, @@ -88213,7 +81575,6 @@ function _prepareSingleTask(taskPath, checkpoint, pendingWrites, processes, chan path: outputTaskPath, writers: [] }; - return task; } else return { id, name: call.name, @@ -88222,17 +81583,17 @@ function _prepareSingleTask(taskPath, checkpoint, pendingWrites, processes, chan }; } else if (taskPath[0] === PUSH) { const index = typeof taskPath[1] === "number" ? taskPath[1] : parseInt(taskPath[1], 10); - if (!channels[constants_TASKS]?.isAvailable()) return void 0; + if (!channels[constants_TASKS]?.isAvailable()) return; const sends = channels[constants_TASKS].get(); - if (index < 0 || index >= sends.length) return void 0; + if (index < 0 || index >= sends.length) return; const packet = _isSendInterface(sends[index]) && !_isSend(sends[index]) ? new Send(sends[index].node, sends[index].args) : sends[index]; if (!_isSendInterface(packet)) { console.warn(`Ignoring invalid packet ${JSON.stringify(packet)} in pending sends.`); - return void 0; + return; } if (!(packet.node in processes)) { console.warn(`Ignoring unknown node name ${packet.node} in pending sends.`); - return void 0; + return; } const triggers = [PUSH]; const checkpointNamespace = parentNamespace === "" ? packet.node : `${parentNamespace}${CHECKPOINT_NAMESPACE_SEPARATOR}${packet.node}`; @@ -88324,7 +81685,7 @@ function _prepareSingleTask(taskPath, checkpoint, pendingWrites, processes, chan } else if (taskPath[0] === PULL) { const name = taskPath[1].toString(); const proc = processes[name]; - if (proc === void 0) return void 0; + if (proc === void 0) return; if (pendingWrites?.length) { const checkpointNamespace = parentNamespace === "" ? name : `${parentNamespace}${CHECKPOINT_NAMESPACE_SEPARATOR}${name}`; const taskId = uuid5(JSON.stringify([ @@ -88334,11 +81695,10 @@ function _prepareSingleTask(taskPath, checkpoint, pendingWrites, processes, chan PULL, name ]), checkpoint.id); - const hasSuccessfulWrites = pendingWrites.some((w) => w[0] === taskId && w[1] !== constants_ERROR); - if (hasSuccessfulWrites) return void 0; + if (pendingWrites.some((w) => w[0] === taskId && w[1] !== constants_ERROR)) return; } const nullVersion = getNullChannelVersion(checkpoint.channel_versions); - if (nullVersion === void 0) return void 0; + if (nullVersion === void 0) return; const seen = checkpoint.versions_seen[name] ?? {}; const trigger = proc.triggers.find((chan) => { if (!channels[chan].isAvailable()) return false; @@ -88346,7 +81706,7 @@ function _prepareSingleTask(taskPath, checkpoint, pendingWrites, processes, chan }); if (trigger !== void 0) { const val = _procInput(proc, channels, forExecution); - if (val === void 0) return void 0; + if (val === void 0) return; const checkpointNamespace = parentNamespace === "" ? name : `${parentNamespace}${CHECKPOINT_NAMESPACE_SEPARATOR}${name}`; const taskId = uuid5(JSON.stringify([ checkpointNamespace, @@ -88436,7 +81796,6 @@ function _prepareSingleTask(taskPath, checkpoint, pendingWrites, processes, chan }; } } - return void 0; } /** * Function injected under CONFIG_KEY_READ in task config, to read current state. @@ -88452,7 +81811,7 @@ function _procInput(proc, channels, forExecution) { for (const [k, chan] of Object.entries(proc.channels)) if (proc.triggers.includes(chan)) try { val[k] = readChannel(channels, chan, false); } catch (e) { - if (e.name === EmptyChannelError.unminifiable_name) return void 0; + if (e.name === EmptyChannelError.unminifiable_name) return; else throw e; } else if (chan in channels) try { @@ -88471,25 +81830,24 @@ function _procInput(proc, channels, forExecution) { if (e.name === EmptyChannelError.unminifiable_name) continue; else throw e; } - if (!successfulRead) return void 0; + if (!successfulRead) return; } else throw new Error(`Invalid channels type, expected list or dict, got ${proc.channels}`); if (forExecution && proc.mapper !== void 0) val = proc.mapper(val); return val; } function _scratchpad({ pendingWrites, taskId, currentTaskInput, resumeMap, namespaceHash }) { const nullResume = pendingWrites.find(([writeTaskId, chan]) => writeTaskId === NULL_TASK_ID && chan === constants_RESUME)?.[2]; - const resume = (() => { - const result = pendingWrites.filter(([writeTaskId, chan]) => writeTaskId === taskId && chan === constants_RESUME).flatMap(([_writeTaskId, _chan, resume$1]) => resume$1); - if (resumeMap != null && namespaceHash in resumeMap) { - const mappedResume = resumeMap[namespaceHash]; - result.push(mappedResume); - } - return result; - })(); const scratchpad = { callCounter: 0, interruptCounter: -1, - resume, + resume: (() => { + const result = pendingWrites.filter(([writeTaskId, chan]) => writeTaskId === taskId && chan === constants_RESUME).flatMap(([_writeTaskId, _chan, resume]) => resume); + if (resumeMap != null && namespaceHash in resumeMap) { + const mappedResume = resumeMap[namespaceHash]; + result.push(mappedResume); + } + return result; + })(), nullResume, subgraphCounter: 0, currentTaskInput, @@ -88499,7 +81857,6 @@ function _scratchpad({ pendingWrites, taskId, currentTaskInput, resumeMap, names pendingWrites.splice(pendingWrites.findIndex(([writeTaskId, chan]) => writeTaskId === NULL_TASK_ID && chan === constants_RESUME), 1); return nullResume; } - return void 0; } }; return scratchpad; @@ -88535,17 +81892,16 @@ const debug_wrap = (color, text) => `${color.start}${text}${color.end}`; function* mapDebugTasks(tasks) { for (const { id, name, input, config, triggers, writes } of tasks) { if (config?.tags?.includes(TAG_HIDDEN)) continue; - const interrupts = writes.filter(([writeId, n]) => { - return writeId === id && n === constants_INTERRUPT; - }).map(([, v]) => { - return v; - }); yield { id, name, input, triggers, - interrupts + interrupts: writes.filter(([writeId, n]) => { + return writeId === id && n === constants_INTERRUPT; + }).map(([, v]) => { + return v; + }) }; } } @@ -88594,8 +81950,7 @@ function* mapDebugCheckpoint(config, channels, streamChannels, metadata, tasks, const parentNs = config.configurable?.checkpoint_ns; const taskStates = {}; for (const task of tasks) { - const candidates = task.subgraphs?.length ? task.subgraphs : [task.proc]; - if (!candidates.find(findSubgraphPregel)) continue; + if (!(task.subgraphs?.length ? task.subgraphs : [task.proc]).find(findSubgraphPregel)) continue; let taskNs = `${task.name}:${task.id}`; if (parentNs) taskNs = `${parentNs}|${taskNs}`; taskStates[task.id] = { configurable: { @@ -88626,7 +81981,6 @@ function tasksWithWrites(tasks, pendingWrites, states, outputKeys) { if (!results.length) return void 0; return mapTaskResultWrites(results); } - return void 0; })(); if (error) return { id: task.id, @@ -88856,9 +82210,8 @@ function toEventStream(stream) { }; } if (mode === "checkpoints") data = _serializeCheckpoint(chunk); - const event = ns?.length ? `${mode}|${ns.join("|")}` : mode; enqueueChunk({ - event, + event: ns?.length ? `${mode}|${ns.join("|")}` : mode, data }); } @@ -88971,8 +82324,7 @@ var PregelLoop = class PregelLoop { hasChannelVersions = true; break; } - const configHasResumingFlag = this.config.configurable?.[CONFIG_KEY_RESUMING] !== void 0; - const configIsResuming = configHasResumingFlag && this.config.configurable?.[CONFIG_KEY_RESUMING]; + const configIsResuming = this.config.configurable?.[CONFIG_KEY_RESUMING] !== void 0 && this.config.configurable?.[CONFIG_KEY_RESUMING]; const inputIsNullOrUndefined = this.input === null || this.input === void 0; const inputIsCommandResuming = isCommand(this.input) && this.input.resume != null; const inputIsResuming = this.input === INPUT_RESUMING; @@ -89193,7 +82545,7 @@ var PregelLoop = class PregelLoop { this.status = "out_of_steps"; return false; } - const nextTasks = _prepareNextTasks(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.config, true, { + this.tasks = _prepareNextTasks(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.config, true, { step: this.step, checkpointer: this.checkpointer, isResuming: this.isResuming, @@ -89203,7 +82555,6 @@ var PregelLoop = class PregelLoop { triggerToNodes: this.triggerToNodes, updatedChannels: this.updatedChannels }); - this.tasks = nextTasks; if (this.checkpointer) this._emit(await gatherIterator(prefixGenerator(mapDebugCheckpoint(this.checkpointConfig, this.channels, this.streamKeys, this.checkpointMetadata, Object.values(this.tasks), this.checkpointPendingWrites, this.prevCheckpointConfig, this.outputKeys), "checkpoints"))); if (Object.values(this.tasks).length === 0) { this.status = "done"; @@ -89603,8 +82954,7 @@ async function _runWithRetry(pregelTask, retryPolicy, configurable, signal) { if (resolvedRetryPolicy === void 0) break; attempts += 1; if (attempts >= (resolvedRetryPolicy.maxAttempts ?? DEFAULT_MAX_RETRIES)) break; - const retryOn = resolvedRetryPolicy.retryOn ?? DEFAULT_RETRY_ON_HANDLER; - if (!retryOn(error)) break; + if (!(resolvedRetryPolicy.retryOn ?? DEFAULT_RETRY_ON_HANDLER)(error)) break; interval = Math.min(resolvedRetryPolicy.maxInterval ?? DEFAULT_MAX_INTERVAL, interval * (resolvedRetryPolicy.backoffFactor ?? DEFAULT_BACKOFF_FACTOR)); const intervalWithJitter = resolvedRetryPolicy.jitter ? Math.floor(interval + Math.random() * 1e3) : interval; await new Promise((resolve) => setTimeout(resolve, intervalWithJitter)); @@ -89838,7 +83188,7 @@ async function runner_call(runner, task, func, name, input, options = {}) { } throw new Error(`BUG: multiple errors found for task ${nextTask.name}__${nextTask.id}`); } - return void 0; + return; } else { const prom = _runWithRetry(nextTask, options.retry, { [constants_CONFIG_KEY_CALL]: runner_call.bind(this, runner, nextTask) }); this.executingTasksMap[nextTask.id] = prom; @@ -90007,10 +83357,9 @@ var Channel = class { if (typeof channels === "string") if (key) channelMappingOrArray = { [key]: channels }; else channelMappingOrArray = [channels]; else channelMappingOrArray = Object.fromEntries(channels.map((chan) => [chan, chan])); - const triggers = Array.isArray(channels) ? channels : [channels]; return new PregelNode({ channels: channelMappingOrArray, - triggers, + triggers: Array.isArray(channels) ? channels : [channels], tags }); } @@ -90481,13 +83830,12 @@ var Pregel = class extends PartialRunnable { } const mergedConfig = mergeConfigs(this.config, config); const saved = await checkpointer.getTuple(config); - const snapshot = await this._prepareStateSnapshot({ + return await this._prepareStateSnapshot({ config: mergedConfig, saved, subgraphCheckpointer: options?.subgraphs ? checkpointer : void 0, applyPendingWrites: !config.configurable?.checkpoint_id }); - return snapshot; } /** * Gets the history of graph states. @@ -90565,12 +83913,11 @@ var Pregel = class extends PartialRunnable { const { values, asNode } = updates[0]; if (values == null && asNode === void 0) { if (updates.length > 1) throw new InvalidUpdateError(`Cannot create empty checkpoint with multiple updates`); - const nextConfig$1 = await checkpointer.put(checkpointConfig, createCheckpoint(checkpoint, void 0, step), { + return patchCheckpointMap(await checkpointer.put(checkpointConfig, createCheckpoint(checkpoint, void 0, step), { source: "update", step: step + 1, parents: saved?.metadata?.parents ?? {} - }, {}); - return patchCheckpointMap(nextConfig$1, saved ? saved.metadata : void 0); + }, {}), saved ? saved.metadata : void 0); } const channels = emptyChannels(this.channels, checkpoint); if (values === null && asNode === END) { @@ -90598,13 +83945,12 @@ var Pregel = class extends PartialRunnable { } _applyWrites(checkpoint, channels, Object.values(nextTasks), checkpointer.getNextVersion.bind(checkpointer), this.triggerToNodes); } - const nextConfig$1 = await checkpointer.put(checkpointConfig, createCheckpoint(checkpoint, channels, step), { + return patchCheckpointMap(await checkpointer.put(checkpointConfig, createCheckpoint(checkpoint, channels, step), { ...checkpointMetadata, source: "update", step: step + 1, parents: saved?.metadata?.parents ?? {} - }, getNewChannelVersions(checkpointPreviousVersions, checkpoint.channel_versions)); - return patchCheckpointMap(nextConfig$1, saved ? saved.metadata : void 0); + }, getNewChannelVersions(checkpointPreviousVersions, checkpoint.channel_versions)), saved ? saved.metadata : void 0); } if (asNode === COPY) { if (updates.length > 1) throw new InvalidUpdateError(`Cannot copy checkpoint with multiple updates`); @@ -90809,7 +84155,7 @@ var Pregel = class extends PartialRunnable { * @internal */ _defaults(config) { - const { debug, streamMode, inputKeys, outputKeys, interruptAfter, interruptBefore,...rest } = config; + const { debug, streamMode, inputKeys, outputKeys, interruptAfter, interruptBefore, ...rest } = config; let streamModeSingle = true; const defaultDebug = debug !== void 0 ? debug : this.debug; let defaultOutputKeys = outputKeys; @@ -90929,7 +84275,7 @@ var Pregel = class extends PartialRunnable { if (inputConfig.recursionLimit === void 0 || inputConfig.recursionLimit < 1) throw new Error(`Passed "recursionLimit" must be at least 1.`); if (this.checkpointer !== void 0 && this.checkpointer !== false && inputConfig.configurable === void 0) throw new Error(`Checkpointer requires one or more of the following "configurable" keys: "thread_id", "checkpoint_ns", "checkpoint_id"`); const validInput = await this._validateInput(input); - const { runId,...restConfig } = inputConfig; + const { runId, ...restConfig } = inputConfig; const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer, store, streamModeSingle, cache, durability] = this._defaults(restConfig); if (typeof config.context !== "undefined") config.context = await this._validateContext(config.context); else config.configurable = await this._validateContext(config.configurable); @@ -90960,8 +84306,7 @@ var Pregel = class extends PartialRunnable { ]); }; config.interrupt ??= this.userInterrupt ?? interrupt; - const callbackManager = await getCallbackManagerForConfig(config); - const runManager = await callbackManager?.handleChainStart(this.toJSON(), utils_coerceToDict(input, "input"), runId, void 0, void 0, void 0, config?.runName ?? this.getName()); + const runManager = await (await getCallbackManagerForConfig(config))?.handleChainStart(this.toJSON(), utils_coerceToDict(input, "input"), runId, void 0, void 0, void 0, config?.runName ?? this.getName()); const channelSpecs = getOnlyChannels(this.channels); let loop; let loopError; @@ -91119,67 +84464,1157 @@ var Pregel = class extends PartialRunnable { ].join(" "), { lc_error_code: "GRAPH_RECURSION_LIMIT" }); } catch (e) { tickError = e; - const suppress = await loop.finishAndHandleError(tickError); - if (!suppress) throw e; + if (!await loop.finishAndHandleError(tickError)) throw e; } finally { if (tickError === void 0) await loop.finishAndHandleError(); } } - async clearCache() { - await this.cache?.clear([]); + async clearCache() { + await this.cache?.clear([]); + } +}; + +//#endregion + +//# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/langgraph/dist/channels/ephemeral_value.js + + + +//#region src/channels/ephemeral_value.ts +/** +* Stores the value received in the step immediately preceding, clears after. +*/ +var EphemeralValue = class EphemeralValue extends BaseChannel { + lc_graph_name = "EphemeralValue"; + guard; + value = []; + constructor(guard = true) { + super(); + this.guard = guard; + } + fromCheckpoint(checkpoint) { + const empty = new EphemeralValue(this.guard); + if (typeof checkpoint !== "undefined") empty.value = [checkpoint]; + return empty; + } + update(values) { + if (values.length === 0) { + const updated = this.value.length > 0; + this.value = []; + return updated; + } + if (values.length !== 1 && this.guard) throw new InvalidUpdateError("EphemeralValue can only receive one value per step."); + this.value = [values[values.length - 1]]; + return true; + } + get() { + if (this.value.length === 0) throw new EmptyChannelError(); + return this.value[0]; + } + checkpoint() { + if (this.value.length === 0) throw new EmptyChannelError(); + return this.value[0]; + } + isAvailable() { + return this.value.length !== 0; } }; //#endregion -//# sourceMappingURL=index.js.map -;// CONCATENATED MODULE: ./node_modules/@langchain/langgraph/dist/channels/ephemeral_value.js +//# sourceMappingURL=ephemeral_value.js.map +;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/iso.js + + +const ZodISODateTime = /*@__PURE__*/ $constructor("ZodISODateTime", (inst, def) => { + $ZodISODateTime.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function iso_datetime(params) { + return _isoDateTime(ZodISODateTime, params); +} +const ZodISODate = /*@__PURE__*/ $constructor("ZodISODate", (inst, def) => { + $ZodISODate.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function iso_date(params) { + return _isoDate(ZodISODate, params); +} +const ZodISOTime = /*@__PURE__*/ $constructor("ZodISOTime", (inst, def) => { + $ZodISOTime.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function iso_time(params) { + return _isoTime(ZodISOTime, params); +} +const ZodISODuration = /*@__PURE__*/ $constructor("ZodISODuration", (inst, def) => { + $ZodISODuration.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function iso_duration(params) { + return _isoDuration(ZodISODuration, params); +} + +;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/errors.js + + +const errors_initializer = (inst, issues) => { + $ZodError.init(inst, issues); + inst.name = "ZodError"; + Object.defineProperties(inst, { + format: { + value: (mapper) => formatError(inst, mapper), + // enumerable: false, + }, + flatten: { + value: (mapper) => flattenError(inst, mapper), + // enumerable: false, + }, + addIssue: { + value: (issue) => inst.issues.push(issue), + // enumerable: false, + }, + addIssues: { + value: (issues) => inst.issues.push(...issues), + // enumerable: false, + }, + isEmpty: { + get() { + return inst.issues.length === 0; + }, + // enumerable: false, + }, + }); + // Object.defineProperty(inst, "isEmpty", { + // get() { + // return inst.issues.length === 0; + // }, + // }); +}; +const errors_ZodError = $constructor("ZodError", errors_initializer); +const ZodRealError = $constructor("ZodError", errors_initializer, { + Parent: Error, +}); +// /** @deprecated Use `z.core.$ZodErrorMapCtx` instead. */ +// export type ErrorMapCtx = core.$ZodErrorMapCtx; + +;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/parse.js + + +const classic_parse_parse = /* @__PURE__ */ _parse(ZodRealError); +const parse_parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError); +const parse_safeParse = /* @__PURE__ */ _safeParse(ZodRealError); +const parse_safeParseAsync = /* @__PURE__ */ _safeParseAsync(ZodRealError); + +;// CONCATENATED MODULE: ./node_modules/zod/v4/classic/schemas.js + + + + + +const schemas_ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => { + $ZodType.init(inst, def); + inst.def = def; + Object.defineProperty(inst, "_def", { value: def }); + // base methods + inst.check = (...checks) => { + return inst.clone({ + ...def, + checks: [ + ...(def.checks ?? []), + ...checks.map((ch) => typeof ch === "function" ? { _zod: { check: ch, def: { check: "custom" }, onattach: [] } } : ch), + ], + } + // { parent: true } + ); + }; + inst.clone = (def, params) => clone(inst, def, params); + inst.brand = () => inst; + inst.register = ((reg, meta) => { + reg.add(inst, meta); + return inst; + }); + // parsing + inst.parse = (data, params) => classic_parse_parse(inst, data, params, { callee: inst.parse }); + inst.safeParse = (data, params) => parse_safeParse(inst, data, params); + inst.parseAsync = async (data, params) => parse_parseAsync(inst, data, params, { callee: inst.parseAsync }); + inst.safeParseAsync = async (data, params) => parse_safeParseAsync(inst, data, params); + inst.spa = inst.safeParseAsync; + // refinements + inst.refine = (check, params) => inst.check(refine(check, params)); + inst.superRefine = (refinement) => inst.check(superRefine(refinement)); + inst.overwrite = (fn) => inst.check(_overwrite(fn)); + // wrappers + inst.optional = () => optional(inst); + inst.nullable = () => nullable(inst); + inst.nullish = () => optional(nullable(inst)); + inst.nonoptional = (params) => nonoptional(inst, params); + inst.array = () => array(inst); + inst.or = (arg) => union([inst, arg]); + inst.and = (arg) => intersection(inst, arg); + inst.transform = (tx) => pipe(inst, transform(tx)); + inst.default = (def) => schemas_default(inst, def); + inst.prefault = (def) => prefault(inst, def); + // inst.coalesce = (def, params) => coalesce(inst, def, params); + inst.catch = (params) => schemas_catch(inst, params); + inst.pipe = (target) => pipe(inst, target); + inst.readonly = () => readonly(inst); + // meta + inst.describe = (description) => { + const cl = inst.clone(); + globalRegistry.add(cl, { description }); + return cl; + }; + Object.defineProperty(inst, "description", { + get() { + return globalRegistry.get(inst)?.description; + }, + configurable: true, + }); + inst.meta = (...args) => { + if (args.length === 0) { + return globalRegistry.get(inst); + } + const cl = inst.clone(); + globalRegistry.add(cl, args[0]); + return cl; + }; + // helpers + inst.isOptional = () => inst.safeParse(undefined).success; + inst.isNullable = () => inst.safeParse(null).success; + return inst; +}); +/** @internal */ +const _ZodString = /*@__PURE__*/ $constructor("_ZodString", (inst, def) => { + $ZodString.init(inst, def); + schemas_ZodType.init(inst, def); + const bag = inst._zod.bag; + inst.format = bag.format ?? null; + inst.minLength = bag.minimum ?? null; + inst.maxLength = bag.maximum ?? null; + // validations + inst.regex = (...args) => inst.check(_regex(...args)); + inst.includes = (...args) => inst.check(_includes(...args)); + inst.startsWith = (...args) => inst.check(_startsWith(...args)); + inst.endsWith = (...args) => inst.check(_endsWith(...args)); + inst.min = (...args) => inst.check(_minLength(...args)); + inst.max = (...args) => inst.check(_maxLength(...args)); + inst.length = (...args) => inst.check(_length(...args)); + inst.nonempty = (...args) => inst.check(_minLength(1, ...args)); + inst.lowercase = (params) => inst.check(_lowercase(params)); + inst.uppercase = (params) => inst.check(_uppercase(params)); + // transforms + inst.trim = () => inst.check(_trim()); + inst.normalize = (...args) => inst.check(_normalize(...args)); + inst.toLowerCase = () => inst.check(_toLowerCase()); + inst.toUpperCase = () => inst.check(_toUpperCase()); +}); +const schemas_ZodString = /*@__PURE__*/ $constructor("ZodString", (inst, def) => { + $ZodString.init(inst, def); + _ZodString.init(inst, def); + inst.email = (params) => inst.check(_email(ZodEmail, params)); + inst.url = (params) => inst.check(_url(ZodURL, params)); + inst.jwt = (params) => inst.check(_jwt(ZodJWT, params)); + inst.emoji = (params) => inst.check(api_emoji(ZodEmoji, params)); + inst.guid = (params) => inst.check(_guid(ZodGUID, params)); + inst.uuid = (params) => inst.check(_uuid(ZodUUID, params)); + inst.uuidv4 = (params) => inst.check(_uuidv4(ZodUUID, params)); + inst.uuidv6 = (params) => inst.check(_uuidv6(ZodUUID, params)); + inst.uuidv7 = (params) => inst.check(_uuidv7(ZodUUID, params)); + inst.nanoid = (params) => inst.check(_nanoid(ZodNanoID, params)); + inst.guid = (params) => inst.check(_guid(ZodGUID, params)); + inst.cuid = (params) => inst.check(_cuid(ZodCUID, params)); + inst.cuid2 = (params) => inst.check(_cuid2(ZodCUID2, params)); + inst.ulid = (params) => inst.check(_ulid(ZodULID, params)); + inst.base64 = (params) => inst.check(_base64(ZodBase64, params)); + inst.base64url = (params) => inst.check(_base64url(ZodBase64URL, params)); + inst.xid = (params) => inst.check(_xid(ZodXID, params)); + inst.ksuid = (params) => inst.check(_ksuid(ZodKSUID, params)); + inst.ipv4 = (params) => inst.check(_ipv4(ZodIPv4, params)); + inst.ipv6 = (params) => inst.check(_ipv6(ZodIPv6, params)); + inst.cidrv4 = (params) => inst.check(_cidrv4(ZodCIDRv4, params)); + inst.cidrv6 = (params) => inst.check(_cidrv6(ZodCIDRv6, params)); + inst.e164 = (params) => inst.check(_e164(ZodE164, params)); + // iso + inst.datetime = (params) => inst.check(iso_datetime(params)); + inst.date = (params) => inst.check(iso_date(params)); + inst.time = (params) => inst.check(iso_time(params)); + inst.duration = (params) => inst.check(iso_duration(params)); +}); +function schemas_string(params) { + return _string(schemas_ZodString, params); +} +const ZodStringFormat = /*@__PURE__*/ $constructor("ZodStringFormat", (inst, def) => { + $ZodStringFormat.init(inst, def); + _ZodString.init(inst, def); +}); +const ZodEmail = /*@__PURE__*/ $constructor("ZodEmail", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodEmail.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_email(params) { + return core._email(ZodEmail, params); +} +const ZodGUID = /*@__PURE__*/ $constructor("ZodGUID", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodGUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_guid(params) { + return core._guid(ZodGUID, params); +} +const ZodUUID = /*@__PURE__*/ $constructor("ZodUUID", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodUUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_uuid(params) { + return core._uuid(ZodUUID, params); +} +function uuidv4(params) { + return core._uuidv4(ZodUUID, params); +} +// ZodUUIDv6 +function uuidv6(params) { + return core._uuidv6(ZodUUID, params); +} +// ZodUUIDv7 +function schemas_uuidv7(params) { + return core._uuidv7(ZodUUID, params); +} +const ZodURL = /*@__PURE__*/ $constructor("ZodURL", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodURL.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function url(params) { + return core._url(ZodURL, params); +} +const ZodEmoji = /*@__PURE__*/ $constructor("ZodEmoji", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodEmoji.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_emoji(params) { + return core._emoji(ZodEmoji, params); +} +const ZodNanoID = /*@__PURE__*/ $constructor("ZodNanoID", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodNanoID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_nanoid(params) { + return core._nanoid(ZodNanoID, params); +} +const ZodCUID = /*@__PURE__*/ $constructor("ZodCUID", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodCUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_cuid(params) { + return core._cuid(ZodCUID, params); +} +const ZodCUID2 = /*@__PURE__*/ $constructor("ZodCUID2", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodCUID2.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_cuid2(params) { + return core._cuid2(ZodCUID2, params); +} +const ZodULID = /*@__PURE__*/ $constructor("ZodULID", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodULID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_ulid(params) { + return core._ulid(ZodULID, params); +} +const ZodXID = /*@__PURE__*/ $constructor("ZodXID", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodXID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_xid(params) { + return core._xid(ZodXID, params); +} +const ZodKSUID = /*@__PURE__*/ $constructor("ZodKSUID", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodKSUID.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_ksuid(params) { + return core._ksuid(ZodKSUID, params); +} +const ZodIPv4 = /*@__PURE__*/ $constructor("ZodIPv4", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodIPv4.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_ipv4(params) { + return core._ipv4(ZodIPv4, params); +} +const ZodIPv6 = /*@__PURE__*/ $constructor("ZodIPv6", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodIPv6.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_ipv6(params) { + return core._ipv6(ZodIPv6, params); +} +const ZodCIDRv4 = /*@__PURE__*/ $constructor("ZodCIDRv4", (inst, def) => { + $ZodCIDRv4.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_cidrv4(params) { + return core._cidrv4(ZodCIDRv4, params); +} +const ZodCIDRv6 = /*@__PURE__*/ $constructor("ZodCIDRv6", (inst, def) => { + $ZodCIDRv6.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_cidrv6(params) { + return core._cidrv6(ZodCIDRv6, params); +} +const ZodBase64 = /*@__PURE__*/ $constructor("ZodBase64", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodBase64.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_base64(params) { + return core._base64(ZodBase64, params); +} +const ZodBase64URL = /*@__PURE__*/ $constructor("ZodBase64URL", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodBase64URL.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_base64url(params) { + return core._base64url(ZodBase64URL, params); +} +const ZodE164 = /*@__PURE__*/ $constructor("ZodE164", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodE164.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function schemas_e164(params) { + return core._e164(ZodE164, params); +} +const ZodJWT = /*@__PURE__*/ $constructor("ZodJWT", (inst, def) => { + // ZodStringFormat.init(inst, def); + $ZodJWT.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function jwt(params) { + return core._jwt(ZodJWT, params); +} +const ZodCustomStringFormat = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodCustomStringFormat", (inst, def) => { + // ZodStringFormat.init(inst, def); + core.$ZodCustomStringFormat.init(inst, def); + ZodStringFormat.init(inst, def); +}))); +function stringFormat(format, fnOrRegex, _params = {}) { + return core._stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params); +} +const schemas_ZodNumber = /*@__PURE__*/ $constructor("ZodNumber", (inst, def) => { + $ZodNumber.init(inst, def); + schemas_ZodType.init(inst, def); + inst.gt = (value, params) => inst.check(_gt(value, params)); + inst.gte = (value, params) => inst.check(_gte(value, params)); + inst.min = (value, params) => inst.check(_gte(value, params)); + inst.lt = (value, params) => inst.check(_lt(value, params)); + inst.lte = (value, params) => inst.check(_lte(value, params)); + inst.max = (value, params) => inst.check(_lte(value, params)); + inst.int = (params) => inst.check(schemas_int(params)); + inst.safe = (params) => inst.check(schemas_int(params)); + inst.positive = (params) => inst.check(_gt(0, params)); + inst.nonnegative = (params) => inst.check(_gte(0, params)); + inst.negative = (params) => inst.check(_lt(0, params)); + inst.nonpositive = (params) => inst.check(_lte(0, params)); + inst.multipleOf = (value, params) => inst.check(_multipleOf(value, params)); + inst.step = (value, params) => inst.check(_multipleOf(value, params)); + // inst.finite = (params) => inst.check(core.finite(params)); + inst.finite = () => inst; + const bag = inst._zod.bag; + inst.minValue = + Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; + inst.maxValue = + Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; + inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? 0.5); + inst.isFinite = true; + inst.format = bag.format ?? null; +}); +function schemas_number(params) { + return _number(schemas_ZodNumber, params); +} +const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def) => { + $ZodNumberFormat.init(inst, def); + schemas_ZodNumber.init(inst, def); +}); +function schemas_int(params) { + return _int(ZodNumberFormat, params); +} +function float32(params) { + return core._float32(ZodNumberFormat, params); +} +function float64(params) { + return core._float64(ZodNumberFormat, params); +} +function int32(params) { + return core._int32(ZodNumberFormat, params); +} +function uint32(params) { + return core._uint32(ZodNumberFormat, params); +} +const schemas_ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => { + $ZodBoolean.init(inst, def); + schemas_ZodType.init(inst, def); +}); +function schemas_boolean(params) { + return _boolean(schemas_ZodBoolean, params); +} +const schemas_ZodBigInt = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodBigInt", (inst, def) => { + core.$ZodBigInt.init(inst, def); + schemas_ZodType.init(inst, def); + inst.gte = (value, params) => inst.check(checks.gte(value, params)); + inst.min = (value, params) => inst.check(checks.gte(value, params)); + inst.gt = (value, params) => inst.check(checks.gt(value, params)); + inst.gte = (value, params) => inst.check(checks.gte(value, params)); + inst.min = (value, params) => inst.check(checks.gte(value, params)); + inst.lt = (value, params) => inst.check(checks.lt(value, params)); + inst.lte = (value, params) => inst.check(checks.lte(value, params)); + inst.max = (value, params) => inst.check(checks.lte(value, params)); + inst.positive = (params) => inst.check(checks.gt(BigInt(0), params)); + inst.negative = (params) => inst.check(checks.lt(BigInt(0), params)); + inst.nonpositive = (params) => inst.check(checks.lte(BigInt(0), params)); + inst.nonnegative = (params) => inst.check(checks.gte(BigInt(0), params)); + inst.multipleOf = (value, params) => inst.check(checks.multipleOf(value, params)); + const bag = inst._zod.bag; + inst.minValue = bag.minimum ?? null; + inst.maxValue = bag.maximum ?? null; + inst.format = bag.format ?? null; +}))); +function schemas_bigint(params) { + return core._bigint(schemas_ZodBigInt, params); +} +const ZodBigIntFormat = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodBigIntFormat", (inst, def) => { + core.$ZodBigIntFormat.init(inst, def); + schemas_ZodBigInt.init(inst, def); +}))); +// int64 +function int64(params) { + return core._int64(ZodBigIntFormat, params); +} +// uint64 +function uint64(params) { + return core._uint64(ZodBigIntFormat, params); +} +const schemas_ZodSymbol = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodSymbol", (inst, def) => { + core.$ZodSymbol.init(inst, def); + schemas_ZodType.init(inst, def); +}))); +function symbol(params) { + return core._symbol(schemas_ZodSymbol, params); +} +const schemas_ZodUndefined = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodUndefined", (inst, def) => { + core.$ZodUndefined.init(inst, def); + schemas_ZodType.init(inst, def); +}))); +function schemas_undefined(params) { + return core._undefined(schemas_ZodUndefined, params); +} + +const schemas_ZodNull = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodNull", (inst, def) => { + core.$ZodNull.init(inst, def); + schemas_ZodType.init(inst, def); +}))); +function schemas_null(params) { + return core._null(schemas_ZodNull, params); +} + +const schemas_ZodAny = /*@__PURE__*/ $constructor("ZodAny", (inst, def) => { + $ZodAny.init(inst, def); + schemas_ZodType.init(inst, def); +}); +function any() { + return _any(schemas_ZodAny); +} +const schemas_ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => { + $ZodUnknown.init(inst, def); + schemas_ZodType.init(inst, def); +}); +function unknown() { + return _unknown(schemas_ZodUnknown); +} +const schemas_ZodNever = /*@__PURE__*/ $constructor("ZodNever", (inst, def) => { + $ZodNever.init(inst, def); + schemas_ZodType.init(inst, def); +}); +function schemas_never(params) { + return _never(schemas_ZodNever, params); +} +const schemas_ZodVoid = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodVoid", (inst, def) => { + core.$ZodVoid.init(inst, def); + schemas_ZodType.init(inst, def); +}))); +function schemas_void(params) { + return core._void(schemas_ZodVoid, params); +} +const schemas_ZodDate = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodDate", (inst, def) => { + core.$ZodDate.init(inst, def); + schemas_ZodType.init(inst, def); + inst.min = (value, params) => inst.check(checks.gte(value, params)); + inst.max = (value, params) => inst.check(checks.lte(value, params)); + const c = inst._zod.bag; + inst.minDate = c.minimum ? new Date(c.minimum) : null; + inst.maxDate = c.maximum ? new Date(c.maximum) : null; +}))); +function schemas_date(params) { + return core._date(schemas_ZodDate, params); +} +const schemas_ZodArray = /*@__PURE__*/ $constructor("ZodArray", (inst, def) => { + $ZodArray.init(inst, def); + schemas_ZodType.init(inst, def); + inst.element = def.element; + inst.min = (minLength, params) => inst.check(_minLength(minLength, params)); + inst.nonempty = (params) => inst.check(_minLength(1, params)); + inst.max = (maxLength, params) => inst.check(_maxLength(maxLength, params)); + inst.length = (len, params) => inst.check(_length(len, params)); + inst.unwrap = () => inst.element; +}); +function array(element, params) { + return _array(schemas_ZodArray, element, params); +} +// .keyof +function keyof(schema) { + const shape = schema._zod.def.shape; + return literal(Object.keys(shape)); +} +const schemas_ZodObject = /*@__PURE__*/ $constructor("ZodObject", (inst, def) => { + $ZodObject.init(inst, def); + schemas_ZodType.init(inst, def); + defineLazy(inst, "shape", () => def.shape); + inst.keyof = () => schemas_enum(Object.keys(inst._zod.def.shape)); + inst.catchall = (catchall) => inst.clone({ ...inst._zod.def, catchall: catchall }); + inst.passthrough = () => inst.clone({ ...inst._zod.def, catchall: unknown() }); + // inst.nonstrict = () => inst.clone({ ...inst._zod.def, catchall: api.unknown() }); + inst.loose = () => inst.clone({ ...inst._zod.def, catchall: unknown() }); + inst.strict = () => inst.clone({ ...inst._zod.def, catchall: schemas_never() }); + inst.strip = () => inst.clone({ ...inst._zod.def, catchall: undefined }); + inst.extend = (incoming) => { + return extend(inst, incoming); + }; + inst.merge = (other) => merge(inst, other); + inst.pick = (mask) => pick(inst, mask); + inst.omit = (mask) => omit(inst, mask); + inst.partial = (...args) => partial(schemas_ZodOptional, inst, args[0]); + inst.required = (...args) => required(ZodNonOptional, inst, args[0]); +}); +function object(shape, params) { + const def = { + type: "object", + get shape() { + assignProp(this, "shape", { ...shape }); + return this.shape; + }, + ...normalizeParams(params), + }; + return new schemas_ZodObject(def); +} +// strictObject +function strictObject(shape, params) { + return new schemas_ZodObject({ + type: "object", + get shape() { + util.assignProp(this, "shape", { ...shape }); + return this.shape; + }, + catchall: schemas_never(), + ...util.normalizeParams(params), + }); +} +// looseObject +function looseObject(shape, params) { + return new schemas_ZodObject({ + type: "object", + get shape() { + util.assignProp(this, "shape", { ...shape }); + return this.shape; + }, + catchall: unknown(), + ...util.normalizeParams(params), + }); +} +const schemas_ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => { + $ZodUnion.init(inst, def); + schemas_ZodType.init(inst, def); + inst.options = def.options; +}); +function union(options, params) { + return new schemas_ZodUnion({ + type: "union", + options: options, + ...normalizeParams(params), + }); +} +const schemas_ZodDiscriminatedUnion = /*@__PURE__*/ $constructor("ZodDiscriminatedUnion", (inst, def) => { + schemas_ZodUnion.init(inst, def); + $ZodDiscriminatedUnion.init(inst, def); +}); +function discriminatedUnion(discriminator, options, params) { + // const [options, params] = args; + return new schemas_ZodDiscriminatedUnion({ + type: "union", + options, + discriminator, + ...normalizeParams(params), + }); +} +const schemas_ZodIntersection = /*@__PURE__*/ $constructor("ZodIntersection", (inst, def) => { + $ZodIntersection.init(inst, def); + schemas_ZodType.init(inst, def); +}); +function intersection(left, right) { + return new schemas_ZodIntersection({ + type: "intersection", + left: left, + right: right, + }); +} +const schemas_ZodTuple = /*@__PURE__*/ $constructor("ZodTuple", (inst, def) => { + $ZodTuple.init(inst, def); + schemas_ZodType.init(inst, def); + inst.rest = (rest) => inst.clone({ + ...inst._zod.def, + rest: rest, + }); +}); +function tuple(items, _paramsOrRest, _params) { + const hasRest = _paramsOrRest instanceof $ZodType; + const params = hasRest ? _params : _paramsOrRest; + const rest = hasRest ? _paramsOrRest : null; + return new schemas_ZodTuple({ + type: "tuple", + items: items, + rest, + ...normalizeParams(params), + }); +} +const schemas_ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => { + $ZodRecord.init(inst, def); + schemas_ZodType.init(inst, def); + inst.keyType = def.keyType; + inst.valueType = def.valueType; +}); +function record(keyType, valueType, params) { + return new schemas_ZodRecord({ + type: "record", + keyType, + valueType: valueType, + ...normalizeParams(params), + }); +} +// type alksjf = core.output; +function partialRecord(keyType, valueType, params) { + return new schemas_ZodRecord({ + type: "record", + keyType: union([keyType, schemas_never()]), + valueType: valueType, + ...util.normalizeParams(params), + }); +} +const schemas_ZodMap = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodMap", (inst, def) => { + core.$ZodMap.init(inst, def); + schemas_ZodType.init(inst, def); + inst.keyType = def.keyType; + inst.valueType = def.valueType; +}))); +function map(keyType, valueType, params) { + return new schemas_ZodMap({ + type: "map", + keyType: keyType, + valueType: valueType, + ...util.normalizeParams(params), + }); +} +const schemas_ZodSet = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodSet", (inst, def) => { + core.$ZodSet.init(inst, def); + schemas_ZodType.init(inst, def); + inst.min = (...args) => inst.check(core._minSize(...args)); + inst.nonempty = (params) => inst.check(core._minSize(1, params)); + inst.max = (...args) => inst.check(core._maxSize(...args)); + inst.size = (...args) => inst.check(core._size(...args)); +}))); +function set(valueType, params) { + return new schemas_ZodSet({ + type: "set", + valueType: valueType, + ...util.normalizeParams(params), + }); +} +const schemas_ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => { + $ZodEnum.init(inst, def); + schemas_ZodType.init(inst, def); + inst.enum = def.entries; + inst.options = Object.values(def.entries); + const keys = new Set(Object.keys(def.entries)); + inst.extract = (values, params) => { + const newEntries = {}; + for (const value of values) { + if (keys.has(value)) { + newEntries[value] = def.entries[value]; + } + else + throw new Error(`Key ${value} not found in enum`); + } + return new schemas_ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries, + }); + }; + inst.exclude = (values, params) => { + const newEntries = { ...def.entries }; + for (const value of values) { + if (keys.has(value)) { + delete newEntries[value]; + } + else + throw new Error(`Key ${value} not found in enum`); + } + return new schemas_ZodEnum({ + ...def, + checks: [], + ...normalizeParams(params), + entries: newEntries, + }); + }; +}); +function schemas_enum(values, params) { + const entries = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values; + return new schemas_ZodEnum({ + type: "enum", + entries, + ...normalizeParams(params), + }); +} +/** @deprecated This API has been merged into `z.enum()`. Use `z.enum()` instead. + * + * ```ts + * enum Colors { red, green, blue } + * z.enum(Colors); + * ``` + */ +function nativeEnum(entries, params) { + return new schemas_ZodEnum({ + type: "enum", + entries, + ...util.normalizeParams(params), + }); +} +const schemas_ZodLiteral = /*@__PURE__*/ $constructor("ZodLiteral", (inst, def) => { + $ZodLiteral.init(inst, def); + schemas_ZodType.init(inst, def); + inst.values = new Set(def.values); + Object.defineProperty(inst, "value", { + get() { + if (def.values.length > 1) { + throw new Error("This schema contains multiple valid literal values. Use `.values` instead."); + } + return def.values[0]; + }, + }); +}); +function literal(value, params) { + return new schemas_ZodLiteral({ + type: "literal", + values: Array.isArray(value) ? value : [value], + ...normalizeParams(params), + }); +} +const ZodFile = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodFile", (inst, def) => { + core.$ZodFile.init(inst, def); + schemas_ZodType.init(inst, def); + inst.min = (size, params) => inst.check(core._minSize(size, params)); + inst.max = (size, params) => inst.check(core._maxSize(size, params)); + inst.mime = (types, params) => inst.check(core._mime(Array.isArray(types) ? types : [types], params)); +}))); +function file(params) { + return core._file(ZodFile, params); +} +const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => { + $ZodTransform.init(inst, def); + schemas_ZodType.init(inst, def); + inst._zod.parse = (payload, _ctx) => { + payload.addIssue = (issue) => { + if (typeof issue === "string") { + payload.issues.push(util_issue(issue, payload.value, def)); + } + else { + // for Zod 3 backwards compatibility + const _issue = issue; + if (_issue.fatal) + _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = inst); + _issue.continue ?? (_issue.continue = true); + payload.issues.push(util_issue(_issue)); + } + }; + const output = def.transform(payload.value, payload); + if (output instanceof Promise) { + return output.then((output) => { + payload.value = output; + return payload; + }); + } + payload.value = output; + return payload; + }; +}); +function transform(fn) { + return new ZodTransform({ + type: "transform", + transform: fn, + }); +} +const schemas_ZodOptional = /*@__PURE__*/ $constructor("ZodOptional", (inst, def) => { + $ZodOptional.init(inst, def); + schemas_ZodType.init(inst, def); + inst.unwrap = () => inst._zod.def.innerType; +}); +function optional(innerType) { + return new schemas_ZodOptional({ + type: "optional", + innerType: innerType, + }); +} +const schemas_ZodNullable = /*@__PURE__*/ $constructor("ZodNullable", (inst, def) => { + $ZodNullable.init(inst, def); + schemas_ZodType.init(inst, def); + inst.unwrap = () => inst._zod.def.innerType; +}); +function nullable(innerType) { + return new schemas_ZodNullable({ + type: "nullable", + innerType: innerType, + }); +} +// nullish +function schemas_nullish(innerType) { + return optional(nullable(innerType)); +} +const schemas_ZodDefault = /*@__PURE__*/ $constructor("ZodDefault", (inst, def) => { + $ZodDefault.init(inst, def); + schemas_ZodType.init(inst, def); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeDefault = inst.unwrap; +}); +function schemas_default(innerType, defaultValue) { + return new schemas_ZodDefault({ + type: "default", + innerType: innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : defaultValue; + }, + }); +} +const ZodPrefault = /*@__PURE__*/ $constructor("ZodPrefault", (inst, def) => { + $ZodPrefault.init(inst, def); + schemas_ZodType.init(inst, def); + inst.unwrap = () => inst._zod.def.innerType; +}); +function prefault(innerType, defaultValue) { + return new ZodPrefault({ + type: "prefault", + innerType: innerType, + get defaultValue() { + return typeof defaultValue === "function" ? defaultValue() : defaultValue; + }, + }); +} +const ZodNonOptional = /*@__PURE__*/ $constructor("ZodNonOptional", (inst, def) => { + $ZodNonOptional.init(inst, def); + schemas_ZodType.init(inst, def); + inst.unwrap = () => inst._zod.def.innerType; +}); +function nonoptional(innerType, params) { + return new ZodNonOptional({ + type: "nonoptional", + innerType: innerType, + ...normalizeParams(params), + }); +} +const ZodSuccess = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodSuccess", (inst, def) => { + core.$ZodSuccess.init(inst, def); + schemas_ZodType.init(inst, def); + inst.unwrap = () => inst._zod.def.innerType; +}))); +function success(innerType) { + return new ZodSuccess({ + type: "success", + innerType: innerType, + }); +} +const schemas_ZodCatch = /*@__PURE__*/ $constructor("ZodCatch", (inst, def) => { + $ZodCatch.init(inst, def); + schemas_ZodType.init(inst, def); + inst.unwrap = () => inst._zod.def.innerType; + inst.removeCatch = inst.unwrap; +}); +function schemas_catch(innerType, catchValue) { + return new schemas_ZodCatch({ + type: "catch", + innerType: innerType, + catchValue: (typeof catchValue === "function" ? catchValue : () => catchValue), + }); +} -//#region src/channels/ephemeral_value.ts -/** -* Stores the value received in the step immediately preceding, clears after. -*/ -var EphemeralValue = class EphemeralValue extends BaseChannel { - lc_graph_name = "EphemeralValue"; - guard; - value = []; - constructor(guard = true) { - super(); - this.guard = guard; - } - fromCheckpoint(checkpoint) { - const empty = new EphemeralValue(this.guard); - if (typeof checkpoint !== "undefined") empty.value = [checkpoint]; - return empty; - } - update(values) { - if (values.length === 0) { - const updated = this.value.length > 0; - this.value = []; - return updated; - } - if (values.length !== 1 && this.guard) throw new InvalidUpdateError("EphemeralValue can only receive one value per step."); - this.value = [values[values.length - 1]]; - return true; - } - get() { - if (this.value.length === 0) throw new EmptyChannelError(); - return this.value[0]; - } - checkpoint() { - if (this.value.length === 0) throw new EmptyChannelError(); - return this.value[0]; - } - isAvailable() { - return this.value.length !== 0; - } -}; +const schemas_ZodNaN = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodNaN", (inst, def) => { + core.$ZodNaN.init(inst, def); + schemas_ZodType.init(inst, def); +}))); +function nan(params) { + return core._nan(schemas_ZodNaN, params); +} +const ZodPipe = /*@__PURE__*/ $constructor("ZodPipe", (inst, def) => { + $ZodPipe.init(inst, def); + schemas_ZodType.init(inst, def); + inst.in = def.in; + inst.out = def.out; +}); +function pipe(in_, out) { + return new ZodPipe({ + type: "pipe", + in: in_, + out: out, + // ...util.normalizeParams(params), + }); +} +const schemas_ZodReadonly = /*@__PURE__*/ $constructor("ZodReadonly", (inst, def) => { + $ZodReadonly.init(inst, def); + schemas_ZodType.init(inst, def); +}); +function readonly(innerType) { + return new schemas_ZodReadonly({ + type: "readonly", + innerType: innerType, + }); +} +const ZodTemplateLiteral = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodTemplateLiteral", (inst, def) => { + core.$ZodTemplateLiteral.init(inst, def); + schemas_ZodType.init(inst, def); +}))); +function templateLiteral(parts, params) { + return new ZodTemplateLiteral({ + type: "template_literal", + parts, + ...util.normalizeParams(params), + }); +} +const schemas_ZodLazy = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodLazy", (inst, def) => { + core.$ZodLazy.init(inst, def); + schemas_ZodType.init(inst, def); + inst.unwrap = () => inst._zod.def.getter(); +}))); +function lazy(getter) { + return new schemas_ZodLazy({ + type: "lazy", + getter: getter, + }); +} +const schemas_ZodPromise = /*@__PURE__*/ (/* unused pure expression or super */ null && (core.$constructor("ZodPromise", (inst, def) => { + core.$ZodPromise.init(inst, def); + schemas_ZodType.init(inst, def); + inst.unwrap = () => inst._zod.def.innerType; +}))); +function promise(innerType) { + return new schemas_ZodPromise({ + type: "promise", + innerType: innerType, + }); +} +const ZodCustom = /*@__PURE__*/ $constructor("ZodCustom", (inst, def) => { + $ZodCustom.init(inst, def); + schemas_ZodType.init(inst, def); +}); +// custom checks +function check(fn) { + const ch = new $ZodCheck({ + check: "custom", + // ...util.normalizeParams(params), + }); + ch._zod.check = fn; + return ch; +} +function schemas_custom(fn, _params) { + return _custom(ZodCustom, fn ?? (() => true), _params); +} +function refine(fn, _params = {}) { + return _refine(ZodCustom, fn, _params); +} +// superRefine +function superRefine(fn) { + const ch = check((payload) => { + payload.addIssue = (issue) => { + if (typeof issue === "string") { + payload.issues.push(util_issue(issue, payload.value, ch._zod.def)); + } + else { + // for Zod 3 backwards compatibility + const _issue = issue; + if (_issue.fatal) + _issue.continue = false; + _issue.code ?? (_issue.code = "custom"); + _issue.input ?? (_issue.input = payload.value); + _issue.inst ?? (_issue.inst = ch); + _issue.continue ?? (_issue.continue = !ch._zod.def.abort); + payload.issues.push(util_issue(_issue)); + } + }; + return fn(payload.value, payload); + }); + return ch; +} +function _instanceof(cls, params = { + error: `Input not instance of ${cls.name}`, +}) { + const inst = new ZodCustom({ + type: "custom", + check: "custom", + fn: (data) => data instanceof cls, + abort: true, + ...util.normalizeParams(params), + }); + inst._zod.bag.Class = cls; + return inst; +} -//#endregion +// stringbool +const stringbool = (...args) => core._stringbool({ + Pipe: ZodPipe, + Boolean: schemas_ZodBoolean, + String: schemas_ZodString, + Transform: ZodTransform, +}, ...args); +function json(params) { + const jsonSchema = lazy(() => { + return union([schemas_string(params), schemas_number(), schemas_boolean(), schemas_null(), array(jsonSchema), record(schemas_string(), jsonSchema)]); + }); + return jsonSchema; +} +// preprocess +// /** @deprecated Use `z.pipe()` and `z.transform()` instead. */ +function preprocess(fn, schema) { + return pipe(transform(fn), schema); +} -//# sourceMappingURL=ephemeral_value.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/langgraph/dist/graph/graph.js @@ -91228,8 +85663,7 @@ var Branch = class { else destinations = result; if (destinations.some((dest) => !dest)) throw new Error("Branch condition returned unknown or null destination"); if (destinations.filter(_isSend).some((packet) => packet.node === END)) throw new InvalidUpdateError("Cannot send a packet to the END node"); - const writeResult = await writer(destinations, config); - return writeResult ?? input; + return await writer(destinations, config) ?? input; } }; var Graph$1 = class { @@ -91364,7 +85798,7 @@ var Graph$1 = class { }; var CompiledGraph = class extends Pregel { builder; - constructor({ builder,...rest }) { + constructor({ builder, ...rest }) { super(rest); this.builder = builder; } @@ -91397,14 +85831,13 @@ var CompiledGraph = class extends Pregel { attachBranch(start, name, branch) { if (start === START && !this.nodes[START]) this.nodes[START] = Channel.subscribeTo(START, { tags: [TAG_HIDDEN] }); this.nodes[start].pipe(branch.run((dests) => { - const writes = dests.map((dest) => { + return new ChannelWrite(dests.map((dest) => { if (_isSend(dest)) return dest; return { channel: dest === END ? END : `branch:${start}:${name}:${dest}`, value: PASSTHROUGH }; - }); - return new ChannelWrite(writes, [TAG_HIDDEN]); + }), [TAG_HIDDEN]); })); const ends = branch.ends ? Object.values(branch.ends) : Object.keys(this.nodes); for (const end of ends) if (end !== END) { @@ -91639,7 +86072,6 @@ var NamedBarrierValue = class NamedBarrierValue extends BaseChannel { } get() { if (!areSetsEqual(this.names, this.seen)) throw new EmptyChannelError(); - return void 0; } checkpoint() { return [...this.seen]; @@ -91690,7 +86122,6 @@ var NamedBarrierValueAfterFinish = class NamedBarrierValueAfterFinish extends Ba } get() { if (!this.finished || !areSetsEqual(this.names, this.seen)) throw new EmptyChannelError(); - return void 0; } checkpoint() { return [[...this.seen], this.finished]; @@ -91794,7 +86225,7 @@ var SchemaMetaRegistry = class { for (const [key, channelSchema] of Object.entries(shape)) { const meta = this.get(channelSchema); if (meta?.reducer) channels[key] = new BinaryOperatorAggregate(meta.reducer.fn, meta.default); - else channels[key] = new LastValue(); + else channels[key] = new LastValue(meta?.default); } return channels; } @@ -92000,13 +86431,9 @@ var StateGraph = class extends Graph$1 { this._schemaDefinition = fields.stateSchema.spec; this._inputDefinition = fields.input?.spec ?? this._schemaDefinition; this._outputDefinition = fields.output?.spec ?? this._schemaDefinition; - } else if (isStateDefinition(fields) || isAnnotationRoot(fields)) { - const spec = isAnnotationRoot(fields) ? fields.spec : fields; - this._schemaDefinition = spec; - } else if (isStateGraphArgs(fields)) { - const spec = _getChannels(fields.channels); - this._schemaDefinition = spec; - } else throw new Error("Invalid StateGraph input. Make sure to pass a valid Annotation.Root or Zod schema."); + } else if (isStateDefinition(fields) || isAnnotationRoot(fields)) this._schemaDefinition = isAnnotationRoot(fields) ? fields.spec : fields; + else if (isStateGraphArgs(fields)) this._schemaDefinition = _getChannels(fields.channels); + else throw new Error("Invalid StateGraph input. Make sure to pass a valid Annotation.Root or Zod schema."); this._inputDefinition ??= this._schemaDefinition; this._outputDefinition ??= this._schemaDefinition; this._addSchema(this._schemaDefinition); @@ -92166,7 +86593,7 @@ var CompiledStateGraph = class extends CompiledGraph { description; /** @internal */ _metaRegistry = schemaMetaRegistry; - constructor({ description,...rest }) { + constructor({ description, ...rest }) { super(rest); this.description = description; } @@ -92291,7 +86718,6 @@ var CompiledStateGraph = class extends CompiledGraph { }; if (isInteropZodObject(input$1)) return apply(input$1); if (input$1 === PartialStateSchema) return interopZodObjectPartial(apply(schema$1)); - return void 0; })(); if (isCommand(input)) { const parsedInput = input; @@ -92347,14 +86773,13 @@ function _controlBranch(value) { return destinations; } function _getControlBranch() { - const CONTROL_BRANCH_PATH = new RunnableCallable({ + return new Branch({ path: new RunnableCallable({ func: _controlBranch, tags: [TAG_HIDDEN], trace: false, recurse: false, name: "" - }); - return new Branch({ path: CONTROL_BRANCH_PATH }); + }) }); } //#endregion @@ -92432,18 +86857,17 @@ var MessageGraph = class extends StateGraph { * @param options RunnableConfig / Runtime coming from node context. */ function pushMessage(message, options) { - const { stateKey: userStateKey,...userConfig } = options ?? {}; + const { stateKey: userStateKey, ...userConfig } = options ?? {}; const config = ensureLangGraphConfig(userConfig); let stateKey = userStateKey ?? "messages"; if (userStateKey === null) stateKey = void 0; const validMessage = coerceMessageLikeToMessage(message); if (!validMessage.id) throw new Error("Message ID is required."); - const callbacks = (() => { + const messagesHandler = (() => { if (Array.isArray(config.callbacks)) return config.callbacks; if (typeof config.callbacks !== "undefined") return config.callbacks.handlers; return []; - })(); - const messagesHandler = callbacks.find((cb) => "name" in cb && cb.name === "StreamMessagesHandler"); + })().find((cb) => "name" in cb && cb.name === "StreamMessagesHandler"); if (messagesHandler) { const metadata = config.metadata ?? {}; const namespace = (metadata.langgraph_checkpoint_ns ?? "").split("|"); @@ -92748,8 +87172,7 @@ entrypoint.final = function final({ value, save }) { * @category Functional API */ function getPreviousState() { - const config = AsyncLocalStorageProviderSingleton.getRunnableConfig(); - return config.configurable?.[CONFIG_KEY_PREVIOUS_STATE]; + return AsyncLocalStorageProviderSingleton.getRunnableConfig().configurable?.[CONFIG_KEY_PREVIOUS_STATE]; } //#endregion @@ -92982,7 +87405,6 @@ var DynamicBarrierValue = class DynamicBarrierValue extends BaseChannel { } get() { if (!this.names || !areSetsEqual(this.names, this.seen)) throw new EmptyChannelError(); - return void 0; } checkpoint() { return [this.names ? [...this.names] : void 0, [...this.seen]]; @@ -93060,6 +87482,29 @@ initializeAsyncLocalStorageSingleton(); //#endregion //# sourceMappingURL=index.js.map +;// CONCATENATED MODULE: ./src/types/agent.types.ts +/** + * Agent types and interfaces for PR Agent + * Following architecture-doc-generator patterns + */ +/** + * Execution mode for LLM-agnostic operation + */ +var ExecutionMode; +(function (ExecutionMode) { + ExecutionMode["EXECUTE"] = "execute"; + ExecutionMode["PROMPT_ONLY"] = "prompt_only"; +})(ExecutionMode || (ExecutionMode = {})); +var AgentPriority; +(function (AgentPriority) { + AgentPriority["HIGH"] = "high"; + AgentPriority["MEDIUM"] = "medium"; + AgentPriority["LOW"] = "low"; +})(AgentPriority || (AgentPriority = {})); + +// EXTERNAL MODULE: external "path" +var external_path_ = __nccwpck_require__(6928); +var external_path_default = /*#__PURE__*/__nccwpck_require__.n(external_path_); ;// CONCATENATED MODULE: ./src/tools/pr-analysis-tools.ts /** * PR Analysis Tools for LangChain Agent @@ -93169,9 +87614,9 @@ function createFileAnalyzerTool() { return new tools_DynamicStructuredTool({ name: 'analyze_file', description: 'Analyze a specific file from the diff to identify risks, complexity, and provide recommendations', - schema: object({ - filePath: schemas_string().describe('Path of the file to analyze'), - diffContent: schemas_string().describe('The diff content for this file'), + schema: objectType({ + filePath: stringType().describe('Path of the file to analyze'), + diffContent: stringType().describe('The diff content for this file'), }), func: async ({ filePath, diffContent }) => { // Parse the diff to extract changes @@ -93225,9 +87670,9 @@ function createRiskDetectorTool() { return new tools_DynamicStructuredTool({ name: 'detect_risks', description: 'Detect security, quality, and breaking change risks in the PR', - schema: object({ - diff: schemas_string().describe('The full diff to analyze for risks'), - context: schemas_string().optional().describe('Additional context about the changes'), + schema: objectType({ + diff: stringType().describe('The full diff to analyze for risks'), + context: stringType().optional().describe('Additional context about the changes'), }), func: async ({ diff, context }) => { const risks = []; @@ -93285,9 +87730,9 @@ function createComplexityScorerTool() { return new tools_DynamicStructuredTool({ name: 'score_complexity', description: 'Calculate overall complexity score for the PR (1-5 scale)', - schema: object({ - filesAnalyzed: array(any()).describe('Array of analyzed files'), - totalChanges: schemas_number().describe('Total lines changed'), + schema: objectType({ + filesAnalyzed: arrayType(anyType()).describe('Array of analyzed files'), + totalChanges: numberType().describe('Total lines changed'), }), func: async ({ filesAnalyzed, totalChanges }) => { let score = 1; @@ -93337,9 +87782,9 @@ function createSummaryGeneratorTool() { return new tools_DynamicStructuredTool({ name: 'generate_summary', description: 'Generate a concise summary of PR changes', - schema: object({ - files: array(any()).describe('Array of changed files'), - title: schemas_string().optional().describe('PR title'), + schema: objectType({ + files: arrayType(anyType()).describe('Array of changed files'), + title: stringType().optional().describe('PR title'), }), func: async ({ files, title }) => { const filesByType = {}; @@ -93420,8 +87865,6 @@ Produce the corrected code now.`; // EXTERNAL MODULE: external "fs" var external_fs_ = __nccwpck_require__(9896); -// EXTERNAL MODULE: external "path" -var external_path_ = __nccwpck_require__(6928); ;// CONCATENATED MODULE: ./src/utils/arch-docs-parser.ts /** * Arch-Docs Parser @@ -93613,368 +88056,2071 @@ function buildArchDocsContext(docs, prContext) { } } } - // Convert to array and sort by relevance - const sortedResults = Array.from(relevantResults.values()) - .sort((a, b) => b.relevance - a.relevance) - .slice(0, 10); // Top 10 most relevant sections - // Build context - const relevantDocs = sortedResults.map(result => ({ - filename: result.doc.filename, - title: result.doc.title, - section: result.section.heading, - content: result.section.content.trim(), - relevance: result.relevance, - })); - // Build summary - const summary = buildContextSummary(docs, relevantDocs); - return { - available: true, - summary, - relevantDocs, - totalDocs: docs.length, - }; + // Convert to array and sort by relevance + const sortedResults = Array.from(relevantResults.values()) + .sort((a, b) => b.relevance - a.relevance) + .slice(0, 10); // Top 10 most relevant sections + // Build context + const relevantDocs = sortedResults.map(result => ({ + filename: result.doc.filename, + title: result.doc.title, + section: result.section.heading, + content: result.section.content.trim(), + relevance: result.relevance, + })); + // Build summary + const summary = buildContextSummary(docs, relevantDocs); + return { + available: true, + summary, + relevantDocs, + totalDocs: docs.length, + }; +} +/** + * Extract keywords from PR context for semantic search + */ +function extractKeywords(prContext) { + const keywords = new Set(); + // From title + if (prContext.title) { + const titleWords = prContext.title + .toLowerCase() + .split(/\s+/) + .filter(w => w.length > 3 && !isCommonWord(w)); + titleWords.forEach(w => keywords.add(w)); + } + // From file paths + for (const file of prContext.files) { + const pathParts = file.path.split(/[\/\-_\.]/); + for (const part of pathParts) { + if (part.length > 3 && !isCommonWord(part.toLowerCase())) { + keywords.add(part.toLowerCase()); + } + } + // Extract from file extensions and directories + if (file.path.includes('test')) + keywords.add('testing'); + if (file.path.includes('api')) + keywords.add('api'); + if (file.path.includes('auth')) + keywords.add('authentication'); + if (file.path.includes('db') || file.path.includes('database')) + keywords.add('database'); + if (file.path.includes('security')) + keywords.add('security'); + if (file.path.includes('schema')) + keywords.add('schema'); + if (file.path.includes('config')) + keywords.add('configuration'); + if (file.path.includes('migration')) + keywords.add('migration'); + } + // From diff content (look for imports, function names, etc.) + if (prContext.diff) { + // Extract import statements + const importMatches = prContext.diff.matchAll(/import\s+.*?\s+from\s+['"]([^'"]+)['"]/g); + for (const match of importMatches) { + const importPath = match[1]; + const parts = importPath.split(/[\/\-_]/); + for (const part of parts) { + if (part.length > 3 && !isCommonWord(part)) { + keywords.add(part); + } + } + } + // Extract class and function names + const classMatches = prContext.diff.matchAll(/class\s+(\w+)/g); + for (const match of classMatches) { + keywords.add(match[1].toLowerCase()); + } + const functionMatches = prContext.diff.matchAll(/function\s+(\w+)/g); + for (const match of functionMatches) { + if (match[1].length > 3) { + keywords.add(match[1].toLowerCase()); + } + } + } + return Array.from(keywords).slice(0, 20); // Limit to top 20 keywords +} +/** + * Check if a word is too common to be useful + */ +function isCommonWord(word) { + const commonWords = new Set([ + 'the', 'and', 'for', 'that', 'this', 'with', 'from', 'have', 'been', + 'will', 'your', 'more', 'when', 'some', 'them', 'than', 'into', 'only', + 'other', 'then', 'also', 'make', 'made', 'like', 'time', 'very', 'just', + 'file', 'code', 'test', 'docs', 'info', 'data', 'type', 'name', 'index', + ]); + return commonWords.has(word); +} +/** + * Build a summary of the context + */ +function buildContextSummary(docs, relevantDocs) { + const docTitles = docs.map(d => d.title).join(', '); + const relevantCount = relevantDocs.length; + let summary = `Architecture Documentation Context:\n`; + summary += `- Total documents: ${docs.length}\n`; + summary += `- Available: ${docTitles}\n`; + summary += `- Relevant sections retrieved: ${relevantCount}\n\n`; + if (relevantCount > 0) { + summary += `Most relevant sections:\n`; + relevantDocs.slice(0, 5).forEach((doc, i) => { + summary += `${i + 1}. ${doc.title} - ${doc.section} (relevance: ${doc.relevance})\n`; + }); + } + return summary; +} +/** + * Format arch-docs context for inclusion in prompts + */ +function formatArchDocsForPrompt(context) { + if (!context.available || context.relevantDocs.length === 0) { + return ''; + } + let prompt = '\n## Repository Architecture Context\n\n'; + prompt += 'The following sections from the architecture documentation are relevant to this PR:\n\n'; + for (const doc of context.relevantDocs) { + prompt += `### ${doc.title} - ${doc.section}\n\n`; + prompt += doc.content + '\n\n'; + prompt += '---\n\n'; + } + return prompt; +} +/** + * Get specific context for risk analysis + */ +function getSecurityContext(docs) { + const securityDoc = docs.find(d => d.filename === 'security'); + if (securityDoc) { + return securityDoc.content; + } + return ''; +} +/** + * Get specific context for architecture understanding + */ +function getArchitectureContext(docs) { + const archDoc = docs.find(d => d.filename === 'architecture'); + if (archDoc) { + return archDoc.content; + } + return ''; +} +/** + * Get specific context for patterns + */ +function getPatternsContext(docs) { + const patternsDoc = docs.find(d => d.filename === 'patterns'); + if (patternsDoc) { + return patternsDoc.content; + } + return ''; +} + +;// CONCATENATED MODULE: ./src/tools/test-suggestion-tool.ts +/** + * Test Suggestion Tool for PR Analysis + * Generates test code suggestions for code changes without corresponding tests + */ + + + + +/** + * Detect test framework from project configuration + */ +function detectTestFramework(repoPath = '.') { + const packageJsonPath = external_node_path_default().join(repoPath, 'package.json'); + // Check for Node.js project + if (external_node_fs_default().existsSync(packageJsonPath)) { + try { + const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, 'utf-8')); + const deps = { + ...packageJson.dependencies, + ...packageJson.devDependencies, + }; + // Check for Jest + if (deps.jest || deps['@jest/core'] || external_node_fs_default().existsSync(external_node_path_default().join(repoPath, 'jest.config.js')) || external_node_fs_default().existsSync(external_node_path_default().join(repoPath, 'jest.config.ts'))) { + return { framework: 'jest', detected: true, configFile: 'jest.config.js' }; + } + // Check for Vitest + if (deps.vitest || external_node_fs_default().existsSync(external_node_path_default().join(repoPath, 'vitest.config.js')) || external_node_fs_default().existsSync(external_node_path_default().join(repoPath, 'vitest.config.ts'))) { + return { framework: 'vitest', detected: true, configFile: 'vitest.config.js' }; + } + // Check for Mocha + if (deps.mocha || external_node_fs_default().existsSync(external_node_path_default().join(repoPath, '.mocharc.js')) || external_node_fs_default().existsSync(external_node_path_default().join(repoPath, '.mocharc.json'))) { + return { framework: 'mocha', detected: true, configFile: '.mocharc.js' }; + } + } + catch (e) { + // Ignore JSON parse errors + } + } + // Check for Python project + const pytestIni = external_node_path_default().join(repoPath, 'pytest.ini'); + const pyprojectToml = external_node_path_default().join(repoPath, 'pyproject.toml'); + const setupPy = external_node_path_default().join(repoPath, 'setup.py'); + if (external_node_fs_default().existsSync(pytestIni)) { + return { framework: 'pytest', detected: true, configFile: 'pytest.ini' }; + } + if (external_node_fs_default().existsSync(pyprojectToml)) { + try { + const content = external_node_fs_default().readFileSync(pyprojectToml, 'utf-8'); + if (content.includes('[tool.pytest]') || content.includes('pytest')) { + return { framework: 'pytest', detected: true, configFile: 'pyproject.toml' }; + } + } + catch (e) { + // Ignore read errors + } + } + if (external_node_fs_default().existsSync(setupPy)) { + try { + const content = external_node_fs_default().readFileSync(setupPy, 'utf-8'); + if (content.includes('pytest')) { + return { framework: 'pytest', detected: true, configFile: 'setup.py' }; + } + } + catch (e) { + // Ignore read errors + } + } + return { framework: 'other', detected: false }; +} +/** + * Check if a file is a test file + */ +function isTestFile(filePath) { + const testPatterns = [ + /\.test\.[jt]sx?$/, + /\.spec\.[jt]sx?$/, + /_test\.py$/, + /test_.*\.py$/, + /\.test\.go$/, + /_test\.go$/, + /Test\.java$/, + /\.test\.rs$/, + ]; + return testPatterns.some(pattern => pattern.test(filePath)); +} +/** + * Check if a file is a code file that should have tests + */ +function isCodeFile(filePath) { + const codeExtensions = ['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.java', '.rs', '.rb', '.cs']; + const ext = external_node_path_default().extname(filePath).toLowerCase(); + // Exclude config files, type definitions, etc. + if (filePath.includes('.d.ts') || filePath.includes('.config.') || filePath.includes('index.')) { + return false; + } + return codeExtensions.includes(ext); +} +/** + * Generate test file path suggestion + */ +function suggestTestFilePath(sourceFilePath, framework) { + const ext = external_node_path_default().extname(sourceFilePath); + const baseName = external_node_path_default().basename(sourceFilePath, ext); + const dirName = external_node_path_default().dirname(sourceFilePath); + // For TypeScript/JavaScript + if (['.ts', '.tsx', '.js', '.jsx'].includes(ext)) { + if (framework === 'jest' || framework === 'vitest') { + // Check if there's a __tests__ folder pattern + if (dirName.includes('src')) { + const testsDir = dirName.replace('src', 'tests'); + return external_node_path_default().join(testsDir, `${baseName}.test${ext}`); + } + return external_node_path_default().join(dirName, `${baseName}.test${ext}`); + } + if (framework === 'mocha') { + return external_node_path_default().join(dirName, `${baseName}.spec${ext}`); + } + } + // For Python + if (ext === '.py') { + return external_node_path_default().join(dirName, `test_${baseName}.py`); + } + // For Go + if (ext === '.go') { + return external_node_path_default().join(dirName, `${baseName}_test.go`); + } + // Default + return external_node_path_default().join(dirName, `${baseName}.test${ext}`); +} +/** + * Create test suggestion tool + */ +function createTestSuggestionTool() { + return new DynamicStructuredTool({ + name: 'suggest_tests', + description: 'Analyze code changes and suggest tests for files without test coverage', + schema: z.object({ + files: z.array(z.object({ + path: z.string(), + diff: z.string(), + additions: z.number(), + })).describe('Array of changed files to analyze'), + framework: z.string().optional().describe('Test framework to use'), + repoPath: z.string().optional().describe('Repository path for framework detection'), + }), + func: async ({ files, framework: providedFramework, repoPath }) => { + const detectedFramework = detectTestFramework(repoPath || '.'); + const testFramework = providedFramework || detectedFramework.framework; + // Filter to code files only + const codeFiles = files.filter(f => isCodeFile(f.path) && !isTestFile(f.path)); + // Check if corresponding test files exist in the PR + const testFilesInPR = files.filter(f => isTestFile(f.path)).map(f => f.path); + const filesNeedingTests = []; + for (const file of codeFiles) { + // Check if a test for this file is included in the PR + const baseNameWithoutExt = path.basename(file.path, path.extname(file.path)); + const hasPRTest = testFilesInPR.some(testPath => testPath.toLowerCase().includes(baseNameWithoutExt.toLowerCase())); + if (!hasPRTest && file.additions > 5) { // Only suggest for files with significant changes + // Extract added code from diff + const addedLines = file.diff + .split('\n') + .filter(line => line.startsWith('+') && !line.startsWith('+++')) + .map(line => line.substring(1)) + .join('\n'); + filesNeedingTests.push({ + file: file.path, + hasPRTest: false, + suggestedTestPath: suggestTestFilePath(file.path, testFramework), + codeSnippet: addedLines.substring(0, 1000), // Limit for context + }); + } + } + return JSON.stringify({ + testFramework, + frameworkDetected: detectedFramework.detected, + configFile: detectedFramework.configFile, + filesAnalyzed: codeFiles.length, + filesNeedingTests: filesNeedingTests.length, + files: filesNeedingTests, + }); + }, + }); +} +/** + * Generate test code template based on framework and code + */ +function generateTestTemplate(framework, filePath, codeSnippet, functionNames = []) { + const baseName = external_node_path_default().basename(filePath, external_node_path_default().extname(filePath)); + const modulePath = filePath.replace(/\.[^/.]+$/, ''); + switch (framework) { + case 'jest': + case 'vitest': + return `import { describe, it, expect } from '${framework === 'vitest' ? 'vitest' : '@jest/globals'}'; +import { /* exported functions */ } from '${modulePath}'; + +describe('${baseName}', () => { +${functionNames.map(fn => ` describe('${fn}', () => { + it('should work correctly', () => { + // TODO: Add test implementation + expect(true).toBe(true); + }); + + it('should handle edge cases', () => { + // TODO: Add edge case tests + }); + }); +`).join('\n') || ` it('should be implemented', () => { + // TODO: Add tests for ${baseName} + expect(true).toBe(true); + }); +`} +}); +`; + case 'mocha': + return `const { expect } = require('chai'); +const { /* exported functions */ } = require('${modulePath}'); + +describe('${baseName}', function() { +${functionNames.map(fn => ` describe('${fn}', function() { + it('should work correctly', function() { + // TODO: Add test implementation + expect(true).to.be.true; + }); + }); +`).join('\n') || ` it('should be implemented', function() { + // TODO: Add tests for ${baseName} + expect(true).to.be.true; + }); +`} +}); +`; + case 'pytest': + return `import pytest +from ${modulePath.replace(/\//g, '.')} import * + +class Test${baseName.charAt(0).toUpperCase() + baseName.slice(1)}: +${functionNames.map(fn => ` def test_${fn}_works(self): + """Test that ${fn} works correctly.""" + # TODO: Add test implementation + assert True + + def test_${fn}_edge_cases(self): + """Test ${fn} edge cases.""" + # TODO: Add edge case tests + assert True +`).join('\n') || ` def test_implementation(self): + """Test ${baseName} functionality.""" + # TODO: Add tests + assert True +`} +`; + default: + return `// TODO: Add tests for ${baseName} +// Detected framework: ${framework} +// +// Test the following functionality: +${functionNames.map(fn => `// - ${fn}`).join('\n') || '// - Main module functionality'} +`; + } +} +/** + * Analyze existing test file and suggest enhancements + */ +function analyzeTestQuality(testFile, sourceFile, framework) { + const testContent = testFile.diff; + const sourceContent = sourceFile.diff; + // Extract existing test cases from the test file + const currentTests = []; + const testPatterns = [ + /(?:test|it|describe)\s*\(\s*['"`]([^'"`]+)['"`]/g, // Jest/Mocha/Vitest + /def\s+test_(\w+)/g, // Python + ]; + for (const pattern of testPatterns) { + let match; + while ((match = pattern.exec(testContent)) !== null) { + currentTests.push(match[1]); + } + } + // Analyze source code to identify testable scenarios + const missingScenarios = []; + const suggestions = []; + // Check for common missing test scenarios + // 1. Error handling tests + if (sourceContent.includes('throw ') || sourceContent.includes('raise ') || + sourceContent.includes('Error(') || sourceContent.includes('Exception(')) { + const hasErrorTests = currentTests.some(t => /error|exception|throw|fail|invalid/i.test(t)); + if (!hasErrorTests) { + missingScenarios.push('Error handling tests'); + suggestions.push('⚠️ Add tests for error conditions and exception handling'); + } + } + // 2. Edge case tests + const hasEdgeCaseTests = currentTests.some(t => /edge|boundary|limit|empty|null|zero|max|min/i.test(t)); + if (!hasEdgeCaseTests && sourceContent.length > 100) { + missingScenarios.push('Edge case tests'); + suggestions.push('🔍 Add tests for edge cases (null, undefined, empty, boundary values)'); + } + // 3. Async operation tests + if ((sourceContent.includes('async ') || sourceContent.includes('await ') || + sourceContent.includes('Promise') || sourceContent.includes('.then(')) && + !testContent.includes('async ')) { + missingScenarios.push('Async operation tests'); + suggestions.push('⏱️ Add async/await tests for asynchronous operations'); + } + // 4. Input validation tests + if (sourceContent.includes('validate') || sourceContent.includes('check') || + sourceContent.match(/if\s*\(/)) { + const hasValidationTests = currentTests.some(t => /valid|invalid|check|verify/i.test(t)); + if (!hasValidationTests) { + missingScenarios.push('Input validation tests'); + suggestions.push('✅ Add tests for input validation and type checking'); + } + } + // 5. Return value tests + const hasReturnTests = currentTests.some(t => /return|result|output|expect/i.test(t)); + if (!hasReturnTests && (sourceContent.includes('return ') || sourceContent.includes('yield '))) { + missingScenarios.push('Return value verification'); + suggestions.push('🎯 Add explicit tests for expected return values and types'); + } + // 6. Side effects and state changes + if (sourceContent.match(/\.\w+\s*=/g) || sourceContent.includes('setState') || + sourceContent.includes('this.')) { + const hasStateTests = currentTests.some(t => /state|change|update|mutate/i.test(t)); + if (!hasStateTests) { + missingScenarios.push('State change tests'); + suggestions.push('🔄 Add tests to verify state changes and side effects'); + } + } + // 7. Integration/interaction tests + if (sourceContent.includes('import ') && currentTests.length < 3) { + suggestions.push('🔗 Consider adding integration tests for component interactions'); + } + // Generate enhancement code suggestions + let enhancementCode = ''; + if (missingScenarios.length > 0) { + enhancementCode = generateEnhancementCode(framework, testFile.path, missingScenarios); + } + return { + testFile: testFile.path, + sourceFile: sourceFile.path, + currentTests, + missingScenarios, + suggestions, + enhancementCode, + }; +} +/** + * Generate code for test enhancements + */ +function generateEnhancementCode(framework, testFilePath, missingScenarios) { + const baseName = external_node_path_default().basename(testFilePath, external_node_path_default().extname(testFilePath)); + switch (framework) { + case 'jest': + case 'vitest': + return ` +// === Suggested Test Enhancements === + +${missingScenarios.includes('Error handling tests') ? ` +describe('Error Handling', () => { + it('should handle invalid input gracefully', () => { + expect(() => functionName(null)).toThrow(); + expect(() => functionName(undefined)).toThrow(); + }); + + it('should throw appropriate error for edge cases', () => { + expect(() => functionName('')).toThrow('Invalid input'); + }); +}); +` : ''} + +${missingScenarios.includes('Edge case tests') ? ` +describe('Edge Cases', () => { + it('should handle empty input', () => { + expect(functionName('')).toBe(expectedEmptyResult); + }); + + it('should handle null and undefined', () => { + expect(functionName(null)).toBe(null); + expect(functionName(undefined)).toBe(undefined); + }); + + it('should handle boundary values', () => { + expect(functionName(0)).toBe(expectedZeroResult); + expect(functionName(Number.MAX_VALUE)).toBeDefined(); + }); +}); +` : ''} + +${missingScenarios.includes('Async operation tests') ? ` +describe('Async Operations', () => { + it('should resolve successfully', async () => { + const result = await asyncFunction(); + expect(result).toBeDefined(); + }); + + it('should handle async errors', async () => { + await expect(asyncFunction('invalid')).rejects.toThrow(); + }); +}); +` : ''} +`; + case 'mocha': + return ` +// === Suggested Test Enhancements === + +${missingScenarios.includes('Error handling tests') ? ` +describe('Error Handling', function() { + it('should handle invalid input gracefully', function() { + expect(() => functionName(null)).to.throw(); + }); +}); +` : ''} + +${missingScenarios.includes('Edge case tests') ? ` +describe('Edge Cases', function() { + it('should handle empty input', function() { + expect(functionName('')).to.equal(expectedEmptyResult); + }); + + it('should handle boundary values', function() { + expect(functionName(0)).to.be.defined; + }); +}); +` : ''} +`; + case 'pytest': + case 'unittest': + return ` +# === Suggested Test Enhancements === + +${missingScenarios.includes('Error handling tests') ? ` +def test_error_handling(): + """Test error handling with invalid inputs.""" + with pytest.raises(ValueError): + function_name(None) + with pytest.raises(ValueError): + function_name('') +` : ''} + +${missingScenarios.includes('Edge case tests') ? ` +def test_edge_cases(): + """Test edge cases and boundary conditions.""" + assert function_name('') == expected_empty_result + assert function_name(0) == expected_zero_result + assert function_name(None) is None +` : ''} + +${missingScenarios.includes('Async operation tests') ? ` +@pytest.mark.asyncio +async def test_async_operations(): + """Test asynchronous operations.""" + result = await async_function() + assert result is not None +` : ''} +`; + default: + return `// Consider adding tests for: ${missingScenarios.join(', ')}`; + } +} +/** + * Format test enhancement for display + */ +function formatTestEnhancement(enhancement) { + let output = `\n### 🔬 Test Enhancement: ${path.basename(enhancement.testFile)}\n\n`; + output += `**Source File:** ${enhancement.sourceFile}\n`; + output += `**Current Tests:** ${enhancement.currentTests.length} test case(s)\n\n`; + if (enhancement.currentTests.length > 0 && enhancement.currentTests.length <= 5) { + output += `**Existing Tests:**\n`; + enhancement.currentTests.forEach(test => { + output += ` ✓ ${test}\n`; + }); + output += `\n`; + } + if (enhancement.missingScenarios.length > 0) { + output += `**Missing Test Scenarios:**\n`; + enhancement.missingScenarios.forEach(scenario => { + output += ` ⚠️ ${scenario}\n`; + }); + output += `\n`; + } + if (enhancement.suggestions.length > 0) { + output += `**Recommendations:**\n`; + enhancement.suggestions.forEach(suggestion => { + output += ` ${suggestion}\n`; + }); + output += `\n`; + } + return output; +} + +;// CONCATENATED MODULE: ./src/tools/devops-cost-estimator.ts +/** + * DevOps Cost Estimator Tool for PR Analysis + * Estimates AWS infrastructure costs for DevOps-related changes (IaC, Dockerfiles, etc.) + * Uses MCP to connect to AWS for cost estimation when available + */ + + +// DevOps file patterns +const DEVOPS_PATTERNS = { + terraform: [/\.tf$/, /\.tfvars$/], + cloudformation: [/template\.(yaml|yml|json)$/, /cloudformation\.(yaml|yml|json)$/], + cdk: [/cdk\.json$/, /\.ts$.*cdk/], + pulumi: [/Pulumi\.(yaml|yml)$/, /pulumi\..*\.(ts|js|py|go)$/], + docker: [/Dockerfile/, /docker-compose\.(yaml|yml)$/], + kubernetes: [/k8s.*\.(yaml|yml)$/, /kubernetes.*\.(yaml|yml)$/, /\.kube.*\.(yaml|yml)$/], + github_actions: [/\.github\/workflows\/.*\.(yaml|yml)$/], + serverless: [/serverless\.(yaml|yml|json)$/], +}; +// AWS resource cost estimates (monthly USD, approximate) +const AWS_RESOURCE_COSTS = { + 'ec2-t3.micro': { min: 8, typical: 8.5, max: 10 }, + 'ec2-t3.small': { min: 15, typical: 17, max: 20 }, + 'ec2-t3.medium': { min: 30, typical: 34, max: 40 }, + 'ec2-t3.large': { min: 60, typical: 68, max: 80 }, + 'ec2-m5.large': { min: 70, typical: 80, max: 95 }, + 'ec2-m5.xlarge': { min: 140, typical: 160, max: 190 }, + 'lambda-1m-invocations': { min: 0.2, typical: 0.4, max: 2 }, + 'lambda-10m-invocations': { min: 2, typical: 4, max: 20 }, + 's3-storage-gb': { min: 0.023, typical: 0.023, max: 0.025 }, + 's3-requests-1k': { min: 0.004, typical: 0.005, max: 0.006 }, + 'rds-db.t3.micro': { min: 13, typical: 15, max: 18 }, + 'rds-db.t3.small': { min: 26, typical: 30, max: 35 }, + 'rds-db.t3.medium': { min: 52, typical: 60, max: 70 }, + 'rds-db.m5.large': { min: 140, typical: 160, max: 190 }, + 'ecs-task-256cpu-512mem': { min: 10, typical: 12, max: 15 }, + 'ecs-task-512cpu-1024mem': { min: 20, typical: 24, max: 30 }, + 'ecs-task-1024cpu-2048mem': { min: 40, typical: 48, max: 60 }, + 'alb': { min: 16, typical: 22, max: 30 }, + 'nat-gateway': { min: 32, typical: 45, max: 60 }, + 'elasticache-t3.micro': { min: 12, typical: 15, max: 18 }, + 'cloudfront-1tb': { min: 85, typical: 100, max: 120 }, + 'api-gateway-1m-requests': { min: 3.5, typical: 4, max: 5 }, + 'sqs-1m-requests': { min: 0.4, typical: 0.5, max: 0.6 }, + 'sns-1m-notifications': { min: 0.5, typical: 0.6, max: 0.7 }, + 'dynamodb-25wcu-25rcu': { min: 25, typical: 30, max: 40 }, +}; +/** + * Check if a file is a DevOps-related file + */ +function isDevOpsFile(filePath) { + for (const [type, patterns] of Object.entries(DEVOPS_PATTERNS)) { + for (const pattern of patterns) { + if (pattern.test(filePath)) { + return { isDevOps: true, type }; + } + } + } + return { isDevOps: false, type: null }; +} +/** + * Extract AWS resources from Terraform content + */ +function extractTerraformResources(content) { + const resources = []; + // Match resource blocks - handles both regular files and diff format (with + prefix) + const resourceRegex = /^[\+\s]*resource\s+"([^"]+)"\s+"([^"]+)"/gm; + let match; + console.error(`[DevOps] Extracting Terraform resources from content length: ${content.length}`); + console.error(`[DevOps] First 200 chars: ${content.substring(0, 200)}`); + while ((match = resourceRegex.exec(content)) !== null) { + const resourceType = match[1]; + const resourceName = match[2]; + console.error(`[DevOps] Found resource: ${resourceType} "${resourceName}"`); + // Map Terraform resources to our cost categories + if (resourceType.startsWith('aws_instance')) { + resources.push({ resource: resourceName, type: 'ec2' }); + } + else if (resourceType.startsWith('aws_lambda')) { + resources.push({ resource: resourceName, type: 'lambda' }); + } + else if (resourceType.startsWith('aws_s3')) { + resources.push({ resource: resourceName, type: 's3' }); + } + else if (resourceType.startsWith('aws_rds') || resourceType.startsWith('aws_db')) { + resources.push({ resource: resourceName, type: 'rds' }); + } + else if (resourceType.startsWith('aws_ecs')) { + resources.push({ resource: resourceName, type: 'ecs' }); + } + else if (resourceType.startsWith('aws_alb') || resourceType.startsWith('aws_lb')) { + resources.push({ resource: resourceName, type: 'alb' }); + } + else if (resourceType.startsWith('aws_nat')) { + resources.push({ resource: resourceName, type: 'nat-gateway' }); + } + else if (resourceType.startsWith('aws_elasticache')) { + resources.push({ resource: resourceName, type: 'elasticache' }); + } + else if (resourceType.startsWith('aws_cloudfront')) { + resources.push({ resource: resourceName, type: 'cloudfront' }); + } + else if (resourceType.startsWith('aws_api_gateway') || resourceType.startsWith('aws_apigatewayv2')) { + resources.push({ resource: resourceName, type: 'api-gateway' }); + } + else if (resourceType.startsWith('aws_sqs')) { + resources.push({ resource: resourceName, type: 'sqs' }); + } + else if (resourceType.startsWith('aws_sns')) { + resources.push({ resource: resourceName, type: 'sns' }); + } + else if (resourceType.startsWith('aws_dynamodb')) { + resources.push({ resource: resourceName, type: 'dynamodb' }); + } + } + console.error(`[DevOps] Extracted ${resources.length} Terraform resources`); + return resources; +} +/** + * Extract AWS resources from CloudFormation content + */ +function extractCloudFormationResources(content) { + const resources = []; + // Simple pattern matching for CFN resources + const typeMap = { + 'AWS::EC2::Instance': 'ec2', + 'AWS::Lambda::Function': 'lambda', + 'AWS::S3::Bucket': 's3', + 'AWS::RDS::DBInstance': 'rds', + 'AWS::ECS::Service': 'ecs', + 'AWS::ECS::TaskDefinition': 'ecs', + 'AWS::ElasticLoadBalancingV2::LoadBalancer': 'alb', + 'AWS::EC2::NatGateway': 'nat-gateway', + 'AWS::ElastiCache::CacheCluster': 'elasticache', + 'AWS::CloudFront::Distribution': 'cloudfront', + 'AWS::ApiGateway::RestApi': 'api-gateway', + 'AWS::ApiGatewayV2::Api': 'api-gateway', + 'AWS::SQS::Queue': 'sqs', + 'AWS::SNS::Topic': 'sns', + 'AWS::DynamoDB::Table': 'dynamodb', + }; + for (const [awsType, costType] of Object.entries(typeMap)) { + if (content.includes(awsType)) { + // Try to extract logical ID + const regex = new RegExp(`(\\w+):\\s*\\n\\s*Type:\\s*['"]?${awsType.replace(/::/g, '::')}`, 'g'); + const matches = content.matchAll(regex); + for (const match of matches) { + resources.push({ resource: match[1] || costType, type: costType }); + } + // Fallback if no match found but type exists + if (resources.filter(r => r.type === costType).length === 0) { + resources.push({ resource: costType, type: costType }); + } + } + } + return resources; +} +/** + * Estimate cost for a resource type + */ +function estimateResourceCost(resourceType) { + // Find matching cost entry + let costKey = ''; + let confidence = 'low'; + switch (resourceType) { + case 'ec2': + costKey = 'ec2-t3.medium'; + confidence = 'medium'; + break; + case 'lambda': + costKey = 'lambda-1m-invocations'; + confidence = 'low'; + break; + case 's3': + costKey = 's3-storage-gb'; + confidence = 'low'; + break; + case 'rds': + costKey = 'rds-db.t3.small'; + confidence = 'medium'; + break; + case 'ecs': + costKey = 'ecs-task-512cpu-1024mem'; + confidence = 'medium'; + break; + case 'alb': + costKey = 'alb'; + confidence = 'high'; + break; + case 'nat-gateway': + costKey = 'nat-gateway'; + confidence = 'high'; + break; + case 'elasticache': + costKey = 'elasticache-t3.micro'; + confidence = 'medium'; + break; + case 'cloudfront': + costKey = 'cloudfront-1tb'; + confidence = 'low'; + break; + case 'api-gateway': + costKey = 'api-gateway-1m-requests'; + confidence = 'low'; + break; + case 'sqs': + costKey = 'sqs-1m-requests'; + confidence = 'low'; + break; + case 'sns': + costKey = 'sns-1m-notifications'; + confidence = 'low'; + break; + case 'dynamodb': + costKey = 'dynamodb-25wcu-25rcu'; + confidence = 'low'; + break; + default: + return { + resource: resourceType, + resourceType, + estimatedNewCost: 0, + confidence: 'low', + details: 'Unknown resource type - manual estimation required', + }; + } + const cost = AWS_RESOURCE_COSTS[costKey]; + if (!cost) { + return { + resource: resourceType, + resourceType, + estimatedNewCost: 0, + confidence: 'low', + details: 'Cost data not available', + }; + } + return { + resource: resourceType, + resourceType, + estimatedNewCost: cost.typical, + confidence, + details: `Estimated $${cost.min.toFixed(2)} - $${cost.max.toFixed(2)}/month`, + }; +} +/** + * Analyze DevOps files and estimate costs + */ +function analyzeDevOpsFiles(files) { + console.error(`[DevOps] Analyzing ${files.length} files`); + const devOpsFiles = files.filter(f => isDevOpsFile(f.path).isDevOps); + console.error(`[DevOps] Found ${devOpsFiles.length} DevOps files:`, devOpsFiles.map(f => f.path)); + if (devOpsFiles.length === 0) { + return { + hasDevOpsChanges: false, + fileTypes: [], + estimates: [], + totalEstimatedCost: 0, + }; + } + const fileTypes = new Set(); + const allResources = []; + for (const file of devOpsFiles) { + const { type } = isDevOpsFile(file.path); + if (type) + fileTypes.add(type); + console.error(`[DevOps] Processing file: ${file.path} (type: ${type})`); + // Get the full content (in real scenario, we'd read the file) + // For now, analyze the diff + const content = file.diff; + if (type === 'terraform') { + allResources.push(...extractTerraformResources(content)); + } + else if (type === 'cloudformation') { + allResources.push(...extractCloudFormationResources(content)); + } + // Add more extractors for other IaC types as needed + } + // Estimate costs for each resource + const estimates = []; + const seenTypes = new Set(); + console.error(`[DevOps] Total resources found: ${allResources.length}`); + for (const resource of allResources) { + if (!seenTypes.has(resource.type)) { + seenTypes.add(resource.type); + const estimate = estimateResourceCost(resource.type); + console.error(`[DevOps] Estimated cost for ${resource.type}: $${estimate.estimatedNewCost}/month`); + estimates.push(estimate); + } + } + const totalEstimatedCost = estimates.reduce((sum, e) => sum + e.estimatedNewCost, 0); + console.error(`[DevOps] Final: ${estimates.length} estimates, total: $${totalEstimatedCost}/month`); + return { + hasDevOpsChanges: true, + fileTypes: Array.from(fileTypes), + estimates, + totalEstimatedCost, + }; +} +/** + * Create DevOps cost estimator tool + */ +function createDevOpsCostEstimatorTool() { + return new DynamicStructuredTool({ + name: 'estimate_devops_costs', + description: 'Analyze DevOps/IaC files and estimate AWS infrastructure costs', + schema: z.object({ + files: z.array(z.object({ + path: z.string(), + diff: z.string(), + })).describe('Array of changed files to analyze'), + awsCredentials: z.object({ + accessKeyId: z.string().optional(), + secretAccessKey: z.string().optional(), + region: z.string().optional(), + }).optional().describe('AWS credentials for live cost lookup (optional)'), + }), + func: async ({ files }) => { + const analysis = analyzeDevOpsFiles(files); + if (!analysis.hasDevOpsChanges) { + return JSON.stringify({ + hasDevOpsChanges: false, + message: 'No DevOps/IaC files detected in changes', + }); + } + return JSON.stringify({ + hasDevOpsChanges: true, + fileTypes: analysis.fileTypes, + estimates: analysis.estimates, + totalEstimatedCost: analysis.totalEstimatedCost, + message: `Detected ${analysis.fileTypes.join(', ')} changes. Estimated monthly cost impact: $${analysis.totalEstimatedCost.toFixed(2)}`, + disclaimer: 'Cost estimates are approximate and based on typical resource sizes. Actual costs depend on usage patterns, region, and specific configurations.', + }); + }, + }); +} +/** + * Format cost estimates for display + */ +function formatCostEstimates(estimates, totalCost) { + if (estimates.length === 0) { + return 'No cost estimates available'; + } + let output = '💰 AWS Cost Estimates\n\n'; + for (const estimate of estimates) { + const emoji = estimate.confidence === 'high' ? '🟢' : estimate.confidence === 'medium' ? '🟡' : '🔴'; + output += `${emoji} ${estimate.resourceType.toUpperCase()}: ~$${estimate.estimatedNewCost.toFixed(2)}/month\n`; + if (estimate.details) { + output += ` ${estimate.details}\n`; + } + } + output += `\n📊 Total Estimated Impact: ~$${totalCost.toFixed(2)}/month\n`; + output += '\n⚠️ Estimates are approximate. Actual costs depend on usage and configuration.\n'; + return output; } + +;// CONCATENATED MODULE: ./src/tools/coverage-reporter.ts /** - * Extract keywords from PR context for semantic search + * Coverage Reporter Tool for PR Analysis + * Reads coverage reports and extracts metrics when coverage tool is configured */ -function extractKeywords(prContext) { - const keywords = new Set(); - // From title - if (prContext.title) { - const titleWords = prContext.title - .toLowerCase() - .split(/\s+/) - .filter(w => w.length > 3 && !isCommonWord(w)); - titleWords.forEach(w => keywords.add(w)); + + + + +// Common coverage file locations +const COVERAGE_PATHS = { + jest: ['coverage/coverage-summary.json', 'coverage/lcov.info', 'coverage/coverage-final.json'], + nyc: ['coverage/coverage-summary.json', '.nyc_output/coverage.json', 'coverage/lcov.info'], + vitest: ['coverage/coverage-summary.json', 'coverage/lcov.info'], + pytest: ['coverage.xml', 'htmlcov/coverage.json', '.coverage'], + generic: ['coverage.json', 'coverage/lcov.info', 'coverage.xml'], +}; +/** + * Detect if coverage tool is configured in the project + */ +function detectCoverageTool(repoPath = '.') { + const packageJsonPath = external_node_path_default().join(repoPath, 'package.json'); + // Check for Node.js project with coverage config + if (external_node_fs_default().existsSync(packageJsonPath)) { + try { + const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, 'utf-8')); + // Check Jest config + if (packageJson.jest?.collectCoverage || packageJson.jest?.coverageDirectory) { + return { tool: 'jest', configured: true }; + } + // Check for coverage scripts + const scripts = packageJson.scripts || {}; + const hasCoverageScript = Object.values(scripts).some((script) => typeof script === 'string' && (script.includes('--coverage') || script.includes('nyc'))); + if (hasCoverageScript) { + // Determine which tool + const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }; + if (deps.jest) + return { tool: 'jest', configured: true }; + if (deps.nyc || deps['istanbul']) + return { tool: 'nyc', configured: true }; + if (deps.vitest) + return { tool: 'vitest', configured: true }; + if (deps.c8) + return { tool: 'c8', configured: true }; + return { tool: 'node', configured: true }; + } + } + catch (e) { + // Ignore parse errors + } } - // From file paths - for (const file of prContext.files) { - const pathParts = file.path.split(/[\/\-_\.]/); - for (const part of pathParts) { - if (part.length > 3 && !isCommonWord(part.toLowerCase())) { - keywords.add(part.toLowerCase()); + // Check for Jest config file + if (external_node_fs_default().existsSync(external_node_path_default().join(repoPath, 'jest.config.js')) || external_node_fs_default().existsSync(external_node_path_default().join(repoPath, 'jest.config.ts'))) { + try { + const configPath = external_node_fs_default().existsSync(external_node_path_default().join(repoPath, 'jest.config.js')) + ? external_node_path_default().join(repoPath, 'jest.config.js') + : external_node_path_default().join(repoPath, 'jest.config.ts'); + const content = external_node_fs_default().readFileSync(configPath, 'utf-8'); + if (content.includes('collectCoverage') || content.includes('coverageDirectory')) { + return { tool: 'jest', configured: true }; } } - // Extract from file extensions and directories - if (file.path.includes('test')) - keywords.add('testing'); - if (file.path.includes('api')) - keywords.add('api'); - if (file.path.includes('auth')) - keywords.add('authentication'); - if (file.path.includes('db') || file.path.includes('database')) - keywords.add('database'); - if (file.path.includes('security')) - keywords.add('security'); - if (file.path.includes('schema')) - keywords.add('schema'); - if (file.path.includes('config')) - keywords.add('configuration'); - if (file.path.includes('migration')) - keywords.add('migration'); + catch (e) { + // Ignore read errors + } } - // From diff content (look for imports, function names, etc.) - if (prContext.diff) { - // Extract import statements - const importMatches = prContext.diff.matchAll(/import\s+.*?\s+from\s+['"]([^'"]+)['"]/g); - for (const match of importMatches) { - const importPath = match[1]; - const parts = importPath.split(/[\/\-_]/); - for (const part of parts) { - if (part.length > 3 && !isCommonWord(part)) { - keywords.add(part); - } + // Check for Python coverage + const setupCfg = external_node_path_default().join(repoPath, 'setup.cfg'); + const pyprojectToml = external_node_path_default().join(repoPath, 'pyproject.toml'); + if (external_node_fs_default().existsSync(setupCfg)) { + try { + const content = external_node_fs_default().readFileSync(setupCfg, 'utf-8'); + if (content.includes('[coverage:') || content.includes('coverage')) { + return { tool: 'pytest-cov', configured: true }; } } - // Extract class and function names - const classMatches = prContext.diff.matchAll(/class\s+(\w+)/g); - for (const match of classMatches) { - keywords.add(match[1].toLowerCase()); + catch (e) { + // Ignore read errors } - const functionMatches = prContext.diff.matchAll(/function\s+(\w+)/g); - for (const match of functionMatches) { - if (match[1].length > 3) { - keywords.add(match[1].toLowerCase()); + } + if (external_node_fs_default().existsSync(pyprojectToml)) { + try { + const content = external_node_fs_default().readFileSync(pyprojectToml, 'utf-8'); + if (content.includes('[tool.coverage]') || content.includes('pytest-cov')) { + return { tool: 'pytest-cov', configured: true }; } } + catch (e) { + // Ignore read errors + } } - return Array.from(keywords).slice(0, 20); // Limit to top 20 keywords + return { tool: null, configured: false }; } /** - * Check if a word is too common to be useful + * Find existing coverage report files */ -function isCommonWord(word) { - const commonWords = new Set([ - 'the', 'and', 'for', 'that', 'this', 'with', 'from', 'have', 'been', - 'will', 'your', 'more', 'when', 'some', 'them', 'than', 'into', 'only', - 'other', 'then', 'also', 'make', 'made', 'like', 'time', 'very', 'just', - 'file', 'code', 'test', 'docs', 'info', 'data', 'type', 'name', 'index', - ]); - return commonWords.has(word); +function findCoverageFiles(repoPath = '.') { + const foundFiles = []; + for (const paths of Object.values(COVERAGE_PATHS)) { + for (const coveragePath of paths) { + const fullPath = external_node_path_default().join(repoPath, coveragePath); + if (external_node_fs_default().existsSync(fullPath)) { + foundFiles.push(fullPath); + } + } + } + return [...new Set(foundFiles)]; // Remove duplicates } /** - * Build a summary of the context + * Parse Jest/NYC coverage-summary.json format */ -function buildContextSummary(docs, relevantDocs) { - const docTitles = docs.map(d => d.title).join(', '); - const relevantCount = relevantDocs.length; - let summary = `Architecture Documentation Context:\n`; - summary += `- Total documents: ${docs.length}\n`; - summary += `- Available: ${docTitles}\n`; - summary += `- Relevant sections retrieved: ${relevantCount}\n\n`; - if (relevantCount > 0) { - summary += `Most relevant sections:\n`; - relevantDocs.slice(0, 5).forEach((doc, i) => { - summary += `${i + 1}. ${doc.title} - ${doc.section} (relevance: ${doc.relevance})\n`; - }); +function parseJestCoverageSummary(filePath) { + try { + const content = JSON.parse(external_node_fs_default().readFileSync(filePath, 'utf-8')); + const total = content.total; + if (!total) + return null; + const fileBreakdown = []; + for (const [file, data] of Object.entries(content)) { + if (file === 'total') + continue; + const fileData = data; + fileBreakdown.push({ + file, + lineCoverage: fileData.lines?.pct || 0, + branchCoverage: fileData.branches?.pct, + }); + } + return { + available: true, + overallPercentage: total.lines?.pct || total.statements?.pct || 0, + lineCoverage: total.lines?.pct, + branchCoverage: total.branches?.pct, + fileBreakdown: fileBreakdown.slice(0, 20), // Limit to 20 files + coverageTool: 'jest/nyc', + }; + } + catch (e) { + return null; } - return summary; } /** - * Format arch-docs context for inclusion in prompts + * Parse LCOV format */ -function formatArchDocsForPrompt(context) { - if (!context.available || context.relevantDocs.length === 0) { - return ''; +function parseLcov(filePath) { + try { + const content = external_node_fs_default().readFileSync(filePath, 'utf-8'); + const files = []; + let currentFile = ''; + let linesHit = 0; + let linesTotal = 0; + for (const line of content.split('\n')) { + if (line.startsWith('SF:')) { + currentFile = line.substring(3); + linesHit = 0; + linesTotal = 0; + } + else if (line.startsWith('LH:')) { + linesHit = parseInt(line.substring(3), 10); + } + else if (line.startsWith('LF:')) { + linesTotal = parseInt(line.substring(3), 10); + } + else if (line === 'end_of_record' && currentFile) { + files.push({ file: currentFile, linesHit, linesTotal }); + currentFile = ''; + } + } + const totalHit = files.reduce((sum, f) => sum + f.linesHit, 0); + const totalLines = files.reduce((sum, f) => sum + f.linesTotal, 0); + const overallPercentage = totalLines > 0 ? (totalHit / totalLines) * 100 : 0; + return { + available: true, + overallPercentage: Math.round(overallPercentage * 100) / 100, + lineCoverage: overallPercentage, + fileBreakdown: files.slice(0, 20).map(f => ({ + file: f.file, + lineCoverage: f.linesTotal > 0 ? (f.linesHit / f.linesTotal) * 100 : 0, + })), + coverageTool: 'lcov', + }; } - let prompt = '\n## Repository Architecture Context\n\n'; - prompt += 'The following sections from the architecture documentation are relevant to this PR:\n\n'; - for (const doc of context.relevantDocs) { - prompt += `### ${doc.title} - ${doc.section}\n\n`; - prompt += doc.content + '\n\n'; - prompt += '---\n\n'; + catch (e) { + return null; } - return prompt; } /** - * Get specific context for risk analysis + * Parse Cobertura XML format */ -function getSecurityContext(docs) { - const securityDoc = docs.find(d => d.filename === 'security'); - if (securityDoc) { - return securityDoc.content; +function parseCobertura(filePath) { + try { + const content = external_node_fs_default().readFileSync(filePath, 'utf-8'); + // Simple regex parsing for line-rate attribute + const lineRateMatch = content.match(/line-rate="([0-9.]+)"/); + const branchRateMatch = content.match(/branch-rate="([0-9.]+)"/); + if (!lineRateMatch) + return null; + const lineRate = parseFloat(lineRateMatch[1]) * 100; + const branchRate = branchRateMatch ? parseFloat(branchRateMatch[1]) * 100 : undefined; + return { + available: true, + overallPercentage: Math.round(lineRate * 100) / 100, + lineCoverage: lineRate, + branchCoverage: branchRate, + coverageTool: 'cobertura', + }; + } + catch (e) { + return null; } - return ''; } /** - * Get specific context for architecture understanding + * Read and parse coverage report */ -function getArchitectureContext(docs) { - const archDoc = docs.find(d => d.filename === 'architecture'); - if (archDoc) { - return archDoc.content; +function readCoverageReport(repoPath = '.') { + const coverageFiles = findCoverageFiles(repoPath); + if (coverageFiles.length === 0) { + return { available: false }; } - return ''; + // Try to parse each file type + for (const filePath of coverageFiles) { + const fileName = external_node_path_default().basename(filePath); + if (fileName === 'coverage-summary.json' || fileName === 'coverage.json') { + const report = parseJestCoverageSummary(filePath); + if (report) + return report; + } + if (fileName === 'lcov.info' || fileName.endsWith('.lcov')) { + const report = parseLcov(filePath); + if (report) + return report; + } + if (fileName === 'coverage.xml' || fileName.endsWith('cobertura.xml')) { + const report = parseCobertura(filePath); + if (report) + return report; + } + } + return { available: false }; } /** - * Get specific context for patterns + * Create coverage reporter tool */ -function getPatternsContext(docs) { - const patternsDoc = docs.find(d => d.filename === 'patterns'); - if (patternsDoc) { - return patternsDoc.content; +function createCoverageReporterTool() { + return new DynamicStructuredTool({ + name: 'report_coverage', + description: 'Read test coverage reports and extract metrics (only if coverage tool is configured)', + schema: z.object({ + repoPath: z.string().optional().describe('Repository path to check for coverage'), + forceRead: z.boolean().optional().describe('Force reading coverage even if not configured'), + }), + func: async ({ repoPath, forceRead }) => { + const projectPath = repoPath || '.'; + // Check if coverage tool is configured + const toolConfig = detectCoverageTool(projectPath); + if (!toolConfig.configured && !forceRead) { + return JSON.stringify({ + available: false, + reason: 'No coverage tool configured in project', + configured: false, + }); + } + // Try to read coverage report + const report = readCoverageReport(projectPath); + return JSON.stringify({ + ...report, + configured: toolConfig.configured, + tool: toolConfig.tool, + }); + }, + }); +} +/** + * Format coverage report for display + */ +function formatCoverageReport(report) { + if (!report.available) { + return 'No coverage data available'; } - return ''; + let output = ''; + if (report.overallPercentage !== undefined) { + const emoji = report.overallPercentage >= 80 ? '🟢' : report.overallPercentage >= 60 ? '🟡' : '🔴'; + output += `${emoji} Overall Coverage: ${report.overallPercentage.toFixed(1)}%\n`; + } + if (report.lineCoverage !== undefined) { + output += ` Lines: ${report.lineCoverage.toFixed(1)}%\n`; + } + if (report.branchCoverage !== undefined) { + output += ` Branches: ${report.branchCoverage.toFixed(1)}%\n`; + } + if (report.delta !== undefined) { + const deltaEmoji = report.delta >= 0 ? '📈' : '📉'; + output += `${deltaEmoji} Coverage Delta: ${report.delta >= 0 ? '+' : ''}${report.delta.toFixed(1)}%\n`; + } + if (report.fileBreakdown && report.fileBreakdown.length > 0) { + output += '\nFile Breakdown:\n'; + for (const file of report.fileBreakdown.slice(0, 10)) { + const emoji = file.lineCoverage >= 80 ? '✅' : file.lineCoverage >= 60 ? '⚠️' : '❌'; + output += ` ${emoji} ${path.basename(file.file)}: ${file.lineCoverage.toFixed(1)}%\n`; + } + if (report.fileBreakdown.length > 10) { + output += ` ... and ${report.fileBreakdown.length - 10} more files\n`; + } + } + return output; } -// EXTERNAL MODULE: external "child_process" -var external_child_process_ = __nccwpck_require__(5317); -// EXTERNAL MODULE: external "util" -var external_util_ = __nccwpck_require__(9023); -;// CONCATENATED MODULE: ./src/utils/semgrep-runner.ts +;// CONCATENATED MODULE: ./src/tools/project-classifier.ts /** - * Semgrep runner utility for static analysis - * Executes Semgrep and processes results + * Project Classifier Tool + * + * Distinguishes between business logic and QA projects based on file patterns, + * content analysis, and project structure. This helps tailor analysis and + * recommendations to the project type. + * + * Business Logic Projects: + * - Focus on feature implementation, data models, APIs, business rules + * - Should prioritize: architecture review, performance, security + * + * QA/Test Projects: + * - Focus on testing, automation, test frameworks + * - Should prioritize: test coverage, test quality, maintainability */ - -const execAsync = (0,external_util_.promisify)(external_child_process_.exec); /** - * Language to Semgrep rule mapping + * Patterns that indicate business logic code */ -const LANGUAGE_RULESETS = { - typescript: ['p/typescript', 'p/javascript', 'p/react', 'p/security-audit'], - javascript: ['p/javascript', 'p/react', 'p/security-audit'], - python: ['p/python', 'p/django', 'p/flask', 'p/security-audit'], - java: ['p/java', 'p/spring', 'p/security-audit'], - go: ['p/golang', 'p/security-audit'], - rust: ['p/rust', 'p/security-audit'], - csharp: ['p/csharp', 'p/security-audit'], - ruby: ['p/ruby', 'p/rails', 'p/security-audit'], - php: ['p/php', 'p/laravel', 'p/security-audit'], -}; -/** - * Check if Semgrep is installed +const BUSINESS_LOGIC_PATTERNS = { + // File patterns + filePatterns: [ + /src\/.*\/(models?|entities|domain)\//i, + /src\/.*\/(services?|business|logic)\//i, + /src\/.*\/(controllers?|handlers?|routes?)\//i, + /src\/.*\/(api|graphql|rest)\//i, + /src\/.*\/(repositories?|dao|database)\//i, + /src\/.*\/(utils?|helpers?|lib)\//i, + /src\/.*\/(components?|views?|pages?)\//i, + ], + // Content patterns (in code) + contentKeywords: [ + 'class ', 'interface ', 'type ', 'enum ', + 'async ', 'await ', 'Promise', + 'export ', 'import ', + 'function', 'const', 'let', + 'router.', 'app.', 'express', + 'schema', 'model', 'entity', + 'query', 'mutation', 'resolver', + 'middleware', 'validation', + 'authentication', 'authorization', + ], +}; +/** + * Patterns that indicate QA/testing code */ -async function isSemgrepInstalled() { - try { - await execAsync('semgrep --version'); - return true; +const QA_TESTING_PATTERNS = { + // File patterns + filePatterns: [ + /test\//i, + /__tests__\//i, + /spec\//i, + /e2e\//i, + /integration\//i, + /\.test\./i, + /\.spec\./i, + /\.e2e\./i, + /cypress\//i, + /playwright\//i, + /selenium\//i, + ], + // Content patterns + contentKeywords: [ + 'describe(', 'it(', 'test(', + 'expect(', 'assert', 'should', + 'beforeEach', 'afterEach', 'beforeAll', 'afterAll', + 'jest.', 'vitest.', 'mocha', + 'cy.', 'page.', 'browser.', + 'fixture', 'mock', 'stub', 'spy', + 'snapshot', 'toMatchSnapshot', + 'toHaveBeenCalled', 'toEqual', 'toBe', + ], +}; +/** + * Classify a project based on changed files + */ +function classifyProject(changedFiles) { + let businessLogicScore = 0; + let qaTestingScore = 0; + const businessLogicSignals = []; + const qaTestingSignals = []; + for (const file of changedFiles) { + const { filename, patch } = file; + // Check file patterns for business logic + for (const pattern of BUSINESS_LOGIC_PATTERNS.filePatterns) { + if (pattern.test(filename)) { + businessLogicScore += 1; + businessLogicSignals.push(`Business logic file: ${filename}`); + break; + } + } + // Check file patterns for QA/testing + for (const pattern of QA_TESTING_PATTERNS.filePatterns) { + if (pattern.test(filename)) { + qaTestingScore += 1; + qaTestingSignals.push(`Test file: ${filename}`); + break; + } + } + // Analyze patch content if available + if (patch) { + // Count business logic keywords + const businessKeywordCount = BUSINESS_LOGIC_PATTERNS.contentKeywords.filter(keyword => patch.includes(keyword)).length; + // Count QA/testing keywords + const qaKeywordCount = QA_TESTING_PATTERNS.contentKeywords.filter(keyword => patch.includes(keyword)).length; + if (businessKeywordCount > qaKeywordCount) { + businessLogicScore += businessKeywordCount * 0.1; + if (businessKeywordCount > 3) { + businessLogicSignals.push(`Business logic code patterns in ${filename}`); + } + } + else if (qaKeywordCount > businessKeywordCount) { + qaTestingScore += qaKeywordCount * 0.1; + if (qaKeywordCount > 3) { + qaTestingSignals.push(`Test code patterns in ${filename}`); + } + } + } } - catch { - return false; + // Calculate total score and confidence + const totalScore = businessLogicScore + qaTestingScore; + const businessLogicRatio = totalScore > 0 ? businessLogicScore / totalScore : 0; + const qaTestingRatio = totalScore > 0 ? qaTestingScore / totalScore : 0; + // Determine project type based on ratios + let projectType; + let confidence; + if (totalScore === 0) { + projectType = 'unknown'; + confidence = 0; + } + else if (businessLogicRatio >= 0.8) { + projectType = 'business_logic'; + confidence = businessLogicRatio; + } + else if (qaTestingRatio >= 0.8) { + projectType = 'qa_testing'; + confidence = qaTestingRatio; + } + else { + projectType = 'mixed'; + confidence = 1 - Math.abs(businessLogicRatio - qaTestingRatio); + } + // Generate type-specific recommendations + const recommendations = generateRecommendations(projectType, { + businessLogicScore, + qaTestingScore, + changedFilesCount: changedFiles.length, + }); + return { + projectType, + confidence, + signals: { + businessLogicSignals, + qaTestingSignals, + }, + recommendations, + }; +} +/** + * Generate recommendations based on project type + */ +function generateRecommendations(projectType, context) { + const recommendations = []; + switch (projectType) { + case 'business_logic': + recommendations.push('📋 **Business Logic Project Detected** - Focus on architecture and data flow review', '🔒 Ensure proper input validation and error handling for business rules', '⚡ Consider performance implications for data processing and API endpoints', '🔐 Review authentication and authorization for sensitive business operations', '📊 Verify data model changes are properly migrated and validated'); + if (context.businessLogicScore > 10) { + recommendations.push('⚠️ Large business logic change - consider breaking into smaller PRs'); + } + break; + case 'qa_testing': + recommendations.push('🧪 **QA/Testing Project Detected** - Focus on test quality and coverage', '✅ Ensure tests are comprehensive and cover edge cases', '🎯 Verify test assertions are meaningful and specific', '♻️ Check for test maintainability and clear test descriptions', '🚀 Consider test execution time and potential for flakiness'); + if (context.qaTestingScore > 10) { + recommendations.push('📈 Extensive test changes - ensure all tests are passing and stable'); + } + break; + case 'mixed': + recommendations.push('🔀 **Mixed Project Type** - Changes span both business logic and tests', '🔄 Ensure business logic changes are properly covered by test changes', '⚖️ Verify test changes reflect the business logic modifications', '📝 Consider separating business logic and test changes into separate commits for clarity'); + break; + case 'unknown': + recommendations.push('❓ **Project Type Unknown** - Unable to determine primary focus', '🔍 Consider adding more context to file organization', '📚 Review if changes follow project structure conventions'); + break; } + return recommendations; } /** - * Get Semgrep rulesets based on language and framework + * Format classification results for display */ -function getSemgrepRulesets(language, framework) { - const rulesets = new Set(['auto', 'p/security-audit', 'p/owasp-top-ten']); - if (language && LANGUAGE_RULESETS[language.toLowerCase()]) { - LANGUAGE_RULESETS[language.toLowerCase()].forEach(r => rulesets.add(r)); +function formatClassification(classification) { + const { projectType, confidence, signals, recommendations } = classification; + let output = `\n## 🏗️ Project Classification\n\n`; + // Project type badge + const typeEmoji = { + business_logic: '💼', + qa_testing: '🧪', + mixed: '🔀', + unknown: '❓', + }; + const typeName = { + business_logic: 'Business Logic', + qa_testing: 'QA/Testing', + mixed: 'Mixed', + unknown: 'Unknown', + }; + output += `**Type:** ${typeEmoji[projectType]} ${typeName[projectType]}\n`; + output += `**Confidence:** ${(confidence * 100).toFixed(0)}%\n\n`; + // Signals + if (signals.businessLogicSignals.length > 0 || signals.qaTestingSignals.length > 0) { + output += `### 🔍 Detection Signals\n\n`; + if (signals.businessLogicSignals.length > 0) { + output += `**Business Logic Indicators:**\n`; + signals.businessLogicSignals.slice(0, 5).forEach(signal => { + output += ` - ${signal}\n`; + }); + if (signals.businessLogicSignals.length > 5) { + output += ` - ...and ${signals.businessLogicSignals.length - 5} more\n`; + } + output += `\n`; + } + if (signals.qaTestingSignals.length > 0) { + output += `**QA/Testing Indicators:**\n`; + signals.qaTestingSignals.slice(0, 5).forEach(signal => { + output += ` - ${signal}\n`; + }); + if (signals.qaTestingSignals.length > 5) { + output += ` - ...and ${signals.qaTestingSignals.length - 5} more\n`; + } + output += `\n`; + } + } + // Recommendations + if (recommendations.length > 0) { + output += `### 💡 Type-Specific Recommendations\n\n`; + recommendations.forEach(rec => { + output += `${rec}\n\n`; + }); } - // Add framework-specific rulesets - if (framework) { - const fw = framework.toLowerCase(); - if (fw.includes('react') || fw.includes('next')) { - rulesets.add('p/react'); + return output; +} +/** + * LangChain tool for project classification + */ +function createProjectClassifierTool() { + return new DynamicStructuredTool({ + name: 'classify_project_type', + description: 'Classifies the project type (business logic vs QA/testing) based on changed files. ' + + 'This helps tailor the PR review to focus on the most relevant aspects. ' + + 'Use this early in the analysis to understand the project context.', + schema: z.object({ + changedFiles: z.array(z.object({ + filename: z.string().describe('The file path'), + patch: z.string().optional().describe('The git diff patch content'), + })).describe('Array of changed files with their content'), + }), + func: async ({ changedFiles }) => { + const classification = classifyProject(changedFiles); + return formatClassification(classification); + }, + }); +} + +// EXTERNAL MODULE: ./node_modules/better-sqlite3/lib/index.js +var lib = __nccwpck_require__(4918); +var lib_default = /*#__PURE__*/__nccwpck_require__.n(lib); +// EXTERNAL MODULE: external "url" +var external_url_ = __nccwpck_require__(7016); +;// CONCATENATED MODULE: ./src/db/index.ts + + + +// Get the directory where this module is located, then navigate to project root +const db_filename = (0,external_url_.fileURLToPath)(import.meta.url); +const db_dirname = external_path_default().dirname(db_filename); +// Resolve DB path relative to the project root (from src/db or dist/db) +// This ensures the database is always in the same location regardless of cwd +function resolveDbPath() { + // Try environment variable first + if (process.env.PR_AGENT_DB_PATH) { + return process.env.PR_AGENT_DB_PATH; + } + // Navigate up from src/db or dist/db to project root + const projectRoot = external_path_default().resolve(db_dirname, '..', '..'); + return __nccwpck_require__.ab + "pr-agent.db"; +} +const DB_PATH = resolveDbPath(); +let db; +function getDB() { + if (!db) { + db = new (lib_default())(DB_PATH); + initDB(); + } + return db; +} +function initDB() { + const db = getDB(); + db.exec(` + CREATE TABLE IF NOT EXISTS pr_analysis ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + pr_number INTEGER, + repo_owner TEXT, + repo_name TEXT, + author TEXT, + title TEXT, + complexity INTEGER, + risks_count INTEGER, + risks TEXT, + recommendations TEXT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + created_tests_count INTEGER, + estimated_cost REAL, + devops_cost_monthly REAL, + devops_resources TEXT, + has_test_suggestions INTEGER, + test_suggestions_count INTEGER, + coverage_percentage REAL, + project_classification TEXT, + peer_review_enabled INTEGER, + ticket_key TEXT, + ticket_quality_score REAL, + ticket_quality_tier TEXT, + ac_compliance_percentage REAL, + ac_requirements_met INTEGER, + ac_requirements_total INTEGER, + peer_review_verdict TEXT, + peer_review_blockers TEXT, + peer_review_warnings TEXT, + implementation_completeness REAL, + quality_score REAL + ) + `); + // Migration: Add columns to existing tables if they don't exist + try { + const tableInfo = db.prepare('PRAGMA table_info(pr_analysis)').all(); + const columnNames = tableInfo.map(col => col.name); + // Dashboard improvements (PR #13) + if (!columnNames.includes('created_tests_count')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN created_tests_count INTEGER DEFAULT 0'); } - else if (fw.includes('vue')) { - rulesets.add('p/javascript'); + if (!columnNames.includes('estimated_cost')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN estimated_cost REAL DEFAULT 0'); } - else if (fw.includes('django')) { - rulesets.add('p/django'); + // DevOps/Infrastructure cost tracking (v0.2.0) + if (!columnNames.includes('devops_cost_monthly')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN devops_cost_monthly REAL'); } - else if (fw.includes('flask')) { - rulesets.add('p/flask'); + if (!columnNames.includes('devops_resources')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN devops_resources TEXT'); } - else if (fw.includes('express')) { - rulesets.add('p/javascript'); + if (!columnNames.includes('has_test_suggestions')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN has_test_suggestions INTEGER'); } - else if (fw.includes('spring')) { - rulesets.add('p/spring'); + if (!columnNames.includes('test_suggestions_count')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN test_suggestions_count INTEGER'); } - else if (fw.includes('rails')) { - rulesets.add('p/rails'); + if (!columnNames.includes('coverage_percentage')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN coverage_percentage REAL'); } - else if (fw.includes('laravel')) { - rulesets.add('p/laravel'); + // Project classification cache (v0.3.0) + if (!columnNames.includes('project_classification')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN project_classification TEXT'); } - } - return Array.from(rulesets); -} -/** - * Run Semgrep analysis on a directory or specific files - */ -async function runSemgrepAnalysis(targetPath, config, language, framework) { - // Check if Semgrep is installed - const installed = await isSemgrepInstalled(); - if (!installed) { - console.warn('⚠️ Semgrep is not installed. Skipping static analysis.'); - console.log(' Install Semgrep: https://semgrep.dev/docs/getting-started/'); - return { - results: [], - errors: [{ - level: 'warning', - type: 'semgrep_not_installed', - message: 'Semgrep is not installed on this system', - }], - }; - } - // Get appropriate rulesets - const rulesets = config.rulesets || getSemgrepRulesets(language, framework); - // Build Semgrep command - const configArgs = rulesets.map(r => `--config ${r}`).join(' '); - const excludeArgs = config.excludePaths - ? config.excludePaths.map(p => `--exclude "${p}"`).join(' ') - : '--exclude "node_modules" --exclude "dist" --exclude "build" --exclude ".git"'; - const timeoutArg = config.timeout ? `--timeout ${config.timeout}` : '--timeout 30'; - const maxFileSizeArg = config.maxFileSize ? `--max-target-bytes ${config.maxFileSize}` : '--max-target-bytes 1000000'; - const command = `semgrep ${configArgs} ${excludeArgs} ${timeoutArg} ${maxFileSizeArg} --json --quiet "${targetPath}"`; - try { - console.log('🔍 Running Semgrep static analysis...'); - const { stdout, stderr } = await execAsync(command, { - maxBuffer: 10 * 1024 * 1024, // 10MB buffer - }); - if (stderr) { - console.warn('Semgrep stderr:', stderr); + // Peer Review / Jira Integration (v0.3.0) + if (!columnNames.includes('peer_review_enabled')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN peer_review_enabled INTEGER'); } - const result = JSON.parse(stdout); - return result; - } - catch (error) { - // Semgrep may exit with non-zero if findings are found - if (error.stdout) { - try { - const result = JSON.parse(error.stdout); - return result; - } - catch { - // Failed to parse JSON - } + if (!columnNames.includes('ticket_key')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ticket_key TEXT'); } - console.error('Semgrep execution error:', error.message); - return { - results: [], - errors: [{ - level: 'error', - type: 'execution_error', - message: error.message, - }], - }; + if (!columnNames.includes('ticket_quality_score')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ticket_quality_score REAL'); + } + if (!columnNames.includes('ticket_quality_tier')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ticket_quality_tier TEXT'); + } + if (!columnNames.includes('ac_compliance_percentage')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ac_compliance_percentage REAL'); + } + if (!columnNames.includes('ac_requirements_met')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ac_requirements_met INTEGER'); + } + if (!columnNames.includes('ac_requirements_total')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ac_requirements_total INTEGER'); + } + if (!columnNames.includes('peer_review_verdict')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN peer_review_verdict TEXT'); + } + if (!columnNames.includes('peer_review_blockers')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN peer_review_blockers TEXT'); + } + if (!columnNames.includes('peer_review_warnings')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN peer_review_warnings TEXT'); + } + if (!columnNames.includes('implementation_completeness')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN implementation_completeness REAL'); + } + if (!columnNames.includes('quality_score')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN quality_score REAL'); + } + } + catch (e) { + // Ignore migration errors - columns may already exist + } +} +function saveAnalysis(record) { + const db = getDB(); + // Prepare values with defaults for all optional fields + const safeRecord = { + ...record, + created_tests_count: record.created_tests_count || 0, + estimated_cost: record.estimated_cost || 0, + coverage_percentage: record.coverage_percentage || null, + // DevOps fields (v0.2.0) + devops_cost_monthly: record.devops_cost_monthly || null, + devops_resources: record.devops_resources || null, + has_test_suggestions: record.has_test_suggestions || null, + test_suggestions_count: record.test_suggestions_count || null, + // Peer review fields (v0.3.0) + peer_review_enabled: record.peer_review_enabled || null, + ticket_key: record.ticket_key || null, + ticket_quality_score: record.ticket_quality_score || null, + ticket_quality_tier: record.ticket_quality_tier || null, + ac_compliance_percentage: record.ac_compliance_percentage || null, + ac_requirements_met: record.ac_requirements_met || null, + ac_requirements_total: record.ac_requirements_total || null, + peer_review_verdict: record.peer_review_verdict || null, + peer_review_blockers: record.peer_review_blockers || null, + peer_review_warnings: record.peer_review_warnings || null, + implementation_completeness: record.implementation_completeness || null, + quality_score: record.quality_score || null, + }; + if (record.timestamp) { + const stmt = db.prepare(` + INSERT INTO pr_analysis ( + pr_number, repo_owner, repo_name, author, title, + complexity, risks_count, risks, recommendations, timestamp, + created_tests_count, estimated_cost, + devops_cost_monthly, devops_resources, has_test_suggestions, test_suggestions_count, coverage_percentage, + project_classification, + peer_review_enabled, ticket_key, ticket_quality_score, ticket_quality_tier, + ac_compliance_percentage, ac_requirements_met, ac_requirements_total, + peer_review_verdict, peer_review_blockers, peer_review_warnings, + implementation_completeness, quality_score + ) VALUES ( + @pr_number, @repo_owner, @repo_name, @author, @title, + @complexity, @risks_count, @risks, @recommendations, @timestamp, + @created_tests_count, @estimated_cost, + @devops_cost_monthly, @devops_resources, @has_test_suggestions, @test_suggestions_count, @coverage_percentage, + @project_classification, + @peer_review_enabled, @ticket_key, @ticket_quality_score, @ticket_quality_tier, + @ac_compliance_percentage, @ac_requirements_met, @ac_requirements_total, + @peer_review_verdict, @peer_review_blockers, @peer_review_warnings, + @implementation_completeness, @quality_score + ) + `); + stmt.run(safeRecord); + } + else { + const stmt = db.prepare(` + INSERT INTO pr_analysis ( + pr_number, repo_owner, repo_name, author, title, + complexity, risks_count, risks, recommendations, + created_tests_count, estimated_cost, + devops_cost_monthly, devops_resources, has_test_suggestions, test_suggestions_count, coverage_percentage, + project_classification, + peer_review_enabled, ticket_key, ticket_quality_score, ticket_quality_tier, + ac_compliance_percentage, ac_requirements_met, ac_requirements_total, + peer_review_verdict, peer_review_blockers, peer_review_warnings, + implementation_completeness, quality_score + ) VALUES ( + @pr_number, @repo_owner, @repo_name, @author, @title, + @complexity, @risks_count, @risks, @recommendations, + @created_tests_count, @estimated_cost, + @devops_cost_monthly, @devops_resources, @has_test_suggestions, @test_suggestions_count, @coverage_percentage, + @project_classification, + @peer_review_enabled, @ticket_key, @ticket_quality_score, @ticket_quality_tier, + @ac_compliance_percentage, @ac_requirements_met, @ac_requirements_total, + @peer_review_verdict, @peer_review_blockers, @peer_review_warnings, + @implementation_completeness, @quality_score + ) + `); + stmt.run(safeRecord); } } /** - * Summarize Semgrep findings + * Get cached project classification for a repository + * Returns the most recent classification if available */ -function summarizeSemgrepFindings(result) { - const findings = result.results || []; - let errorCount = 0; - let warningCount = 0; - let infoCount = 0; - const categoriesSet = new Set(); - const filesSet = new Set(); - const criticalFindings = []; - findings.forEach(finding => { - const severity = finding.extra.severity; - if (severity === 'ERROR') { - errorCount++; - criticalFindings.push(finding); - } - else if (severity === 'WARNING') { - warningCount++; +function getProjectClassification(repoOwner, repoName) { + const db = getDB(); + const result = db.prepare(` + SELECT project_classification + FROM pr_analysis + WHERE repo_owner = ? AND repo_name = ? AND project_classification IS NOT NULL + ORDER BY timestamp DESC + LIMIT 1 + `).get(repoOwner, repoName); + return result?.project_classification || null; +} +function getCommonRecommendations(limit = 5) { + const db = getDB(); + const rows = db.prepare('SELECT recommendations FROM pr_analysis').all(); + const frequency = {}; + rows.forEach(row => { + try { + const recs = JSON.parse(row.recommendations); + recs.forEach(rec => { + // Simple normalization: first 50 chars to group similar start phrases + // In reality, this needs NLP clustering, but simple grouping works for identical strings + const key = rec.trim(); + frequency[key] = (frequency[key] || 0) + 1; + }); } - else { - infoCount++; + catch (e) { + // ignore parse errors } - // Track categories - const category = finding.extra.metadata.category || 'unknown'; - categoriesSet.add(category); - // Track files - filesSet.add(finding.path); }); + return Object.entries(frequency) + .sort((a, b) => b[1] - a[1]) // Descending order + .slice(0, limit) + .map(([text, count]) => ({ text, count })); +} +function getComplexityDistribution() { + const db = getDB(); + // Group by complexity buckets + const rows = db.prepare(` + SELECT + CASE + WHEN complexity <= 2 THEN 'Low' + WHEN complexity <= 4 THEN 'Medium' + ELSE 'High' + END as category, + COUNT(*) as count + FROM pr_analysis + GROUP BY category + `).all(); + const distribution = { Low: 0, Medium: 0, High: 0 }; + rows.forEach(r => { + if (r.category === 'Low') + distribution.Low = r.count; + else if (r.category === 'Medium') + distribution.Medium = r.count; + else if (r.category === 'High') + distribution.High = r.count; + }); + return Object.values(distribution); // [Low, Medium, High] +} +function getWeeklyQualityTrend() { + const db = getDB(); + // SQLite doesn't have great date functions, so we'll group by YYYY-MM-DD and aggregate in JS or simple substr + // Grouping by day for better granularity, frontend can aggregate to weeks if needed + const rows = db.prepare(` + SELECT + substr(timestamp, 1, 10) as date, + AVG(complexity) as avg_complexity, + COUNT(*) as count + FROM pr_analysis + GROUP BY date + ORDER BY date ASC + LIMIT 30 + `).all(); + return rows; +} +function getDashboardStats() { + const db = getDB(); + // Total PRs + const totalPRs = db.prepare('SELECT COUNT(*) as count FROM pr_analysis').get(); + // "Successful" PRs (defined as complexity < 3 and 0 risks for this MVP) + const successfulPRs = db.prepare('SELECT COUNT(*) as count FROM pr_analysis WHERE complexity < 3 AND risks_count = 0').get(); + // Average Complexity + const avgComplexity = db.prepare('SELECT AVG(complexity) as avg FROM pr_analysis').get(); + // Stats per Creator + const perCreator = db.prepare(` + SELECT author, COUNT(*) as count, AVG(complexity) as avg_complexity + FROM pr_analysis + GROUP BY author + ORDER BY count DESC + LIMIT 10 + `).all(); + const commonRecommendations = getCommonRecommendations(5); + const complexityDistribution = getComplexityDistribution(); + const qualityTrend = getWeeklyQualityTrend(); + // New Aggregations + const totalTestsCreated = db.prepare('SELECT SUM(created_tests_count) as count FROM pr_analysis').get(); + const avgCoverage = db.prepare('SELECT AVG(coverage_percentage) as avg FROM pr_analysis WHERE coverage_percentage IS NOT NULL').get(); + const terraformCost = db.prepare('SELECT SUM(estimated_cost) as cost FROM pr_analysis').get(); + // Jira Compliance Stats (v0.3.0) + const jiraComplianceStats = getJiraComplianceStats(); return { - totalFindings: findings.length, - errorCount, - warningCount, - infoCount, - categoriesAffected: Array.from(categoriesSet), - criticalFindings: criticalFindings, - filesWithIssues: Array.from(filesSet), + totalPRs: totalPRs.count, + successRate: totalPRs.count > 0 ? (successfulPRs.count / totalPRs.count) * 100 : 0, + avgComplexity: avgComplexity.avg || 0, + perCreator, + commonRecommendations, + complexityDistribution, + qualityTrend, + // Dashboard improvements (PR #13) + metrics: { + testsCreated: totalTestsCreated.count || 0, + avgCoverage: avgCoverage.avg || 0, + terraformCost: terraformCost.cost || 0 + }, + // DevOps/Infrastructure cost data (v0.2.0) + devOpsCosts: getDevOpsCostStats(), + // Jira Compliance (v0.3.0) + jiraCompliance: jiraComplianceStats, }; } +function getRecentAnalyses(limit = 10) { + const db = getDB(); + return db.prepare('SELECT * FROM pr_analysis ORDER BY timestamp DESC LIMIT ?').all(limit); +} /** - * Filter Semgrep findings by changed files + * Get DevOps/Infrastructure cost statistics */ -function filterFindingsByChangedFiles(findings, changedFiles) { - const changedFileSet = new Set(changedFiles.map(f => external_path_.normalize(f))); - return findings.filter(finding => { - const normalizedPath = external_path_.normalize(finding.path); - return changedFileSet.has(normalizedPath) || - changedFiles.some(cf => normalizedPath.includes(cf) || cf.includes(normalizedPath)); - }); +function getDevOpsCostStats() { + const db = getDB(); + // Total DevOps cost estimates + const devOpsTotals = db.prepare(` + SELECT + COALESCE(SUM(devops_cost_monthly), 0) as total_monthly, + COUNT(CASE WHEN devops_cost_monthly > 0 THEN 1 END) as analyses_with_devops + FROM pr_analysis + WHERE devops_cost_monthly IS NOT NULL + `).get(); + // Resource type breakdown (from JSON column) + const resourceRows = db.prepare(` + SELECT devops_resources + FROM pr_analysis + WHERE devops_resources IS NOT NULL AND devops_resources != '' + `).all(); + const resourceTypes = {}; + for (const row of resourceRows) { + try { + const resources = JSON.parse(row.devops_resources); + for (const resource of resources) { + resourceTypes[resource.resourceType] = (resourceTypes[resource.resourceType] || 0) + 1; + } + } + catch (e) { + // Ignore parse errors + } + } + // Cost trend (last 30 days) + const costTrend = db.prepare(` + SELECT + substr(timestamp, 1, 10) as date, + COALESCE(SUM(devops_cost_monthly), 0) as cost + FROM pr_analysis + WHERE devops_cost_monthly IS NOT NULL + AND timestamp >= datetime('now', '-30 days') + GROUP BY date + ORDER BY date ASC + `).all(); + // Test suggestion stats + const testStats = db.prepare(` + SELECT + COUNT(CASE WHEN has_test_suggestions = 1 THEN 1 END) as analyses_with_suggestions, + COALESCE(SUM(test_suggestions_count), 0) as total_suggestions + FROM pr_analysis + `).get(); + // Coverage stats + const coverageStats = db.prepare(` + SELECT + COUNT(CASE WHEN coverage_percentage IS NOT NULL THEN 1 END) as analyses_with_coverage, + COALESCE(AVG(coverage_percentage), 0) as avg_coverage + FROM pr_analysis + WHERE coverage_percentage IS NOT NULL + `).get(); + return { + totalMonthlyEstimate: devOpsTotals.total_monthly, + analysesWithDevOps: devOpsTotals.analyses_with_devops, + averageDevOpsCost: devOpsTotals.analyses_with_devops > 0 + ? devOpsTotals.total_monthly / devOpsTotals.analyses_with_devops + : 0, + resourceTypes, + costTrend, + testSuggestionStats: { + analysesWithSuggestions: testStats.analyses_with_suggestions, + totalSuggestions: testStats.total_suggestions, + }, + coverageStats: { + analysesWithCoverage: coverageStats.analyses_with_coverage, + averageCoverage: coverageStats.avg_coverage, + }, + }; } /** - * Format Semgrep finding for display + * Get Jira compliance statistics for the dashboard */ -function formatSemgrepFinding(finding) { - const severity = finding.extra.severity; - const icon = severity === 'ERROR' ? '❌' : severity === 'WARNING' ? '⚠️' : 'ℹ️'; - return `${icon} [${severity}] ${finding.extra.message} - File: ${finding.path}:${finding.start.line} - Rule: ${finding.check_id} - ${finding.extra.metadata.category ? `Category: ${finding.extra.metadata.category}` : ''}`; +function getJiraComplianceStats() { + const db = getDB(); + // Count PRs with peer review enabled + const peerReviewCounts = db.prepare(` + SELECT + COUNT(CASE WHEN peer_review_enabled = 1 THEN 1 END) as total_with_peer_review, + COUNT(CASE WHEN peer_review_enabled = 1 AND ac_compliance_percentage >= 70 THEN 1 END) as satisfied, + COUNT(CASE WHEN peer_review_enabled = 1 AND ac_compliance_percentage < 70 THEN 1 END) as missed + FROM pr_analysis + `).get(); + // Average scores + const avgScores = db.prepare(` + SELECT + COALESCE(AVG(ticket_quality_score), 0) as avg_ticket_quality, + COALESCE(AVG(ac_compliance_percentage), 0) as avg_ac_compliance + FROM pr_analysis + WHERE peer_review_enabled = 1 + `).get(); + // Verdict breakdown + const verdictCounts = db.prepare(` + SELECT + COUNT(CASE WHEN peer_review_verdict = 'approve' THEN 1 END) as approved, + COUNT(CASE WHEN peer_review_verdict = 'request_changes' THEN 1 END) as request_changes, + COUNT(CASE WHEN peer_review_verdict = 'needs_discussion' THEN 1 END) as needs_discussion + FROM pr_analysis + WHERE peer_review_enabled = 1 + `).get(); + // Ticket quality tier breakdown + const tierCounts = db.prepare(` + SELECT + COUNT(CASE WHEN ticket_quality_tier = 'excellent' THEN 1 END) as excellent, + COUNT(CASE WHEN ticket_quality_tier = 'good' THEN 1 END) as good, + COUNT(CASE WHEN ticket_quality_tier = 'adequate' THEN 1 END) as adequate, + COUNT(CASE WHEN ticket_quality_tier = 'poor' THEN 1 END) as poor, + COUNT(CASE WHEN ticket_quality_tier = 'insufficient' THEN 1 END) as insufficient + FROM pr_analysis + WHERE peer_review_enabled = 1 + `).get(); + return { + satisfied: peerReviewCounts.satisfied, + missed: peerReviewCounts.missed, + totalWithPeerReview: peerReviewCounts.total_with_peer_review, + averageTicketQuality: avgScores.avg_ticket_quality, + averageACCompliance: avgScores.avg_ac_compliance, + verdictBreakdown: { + approved: verdictCounts.approved, + requestChanges: verdictCounts.request_changes, + needsDiscussion: verdictCounts.needs_discussion, + }, + ticketQualityTiers: { + excellent: tierCounts.excellent, + good: tierCounts.good, + adequate: tierCounts.adequate, + poor: tierCounts.poor, + insufficient: tierCounts.insufficient, + }, + }; } ;// CONCATENATED MODULE: ./src/agents/base-pr-agent-workflow.ts @@ -93988,6 +90134,12 @@ function formatSemgrepFinding(finding) { + + + + + + /** * Agent workflow state */ @@ -94011,10 +90163,14 @@ const PRAgentState = Annotation.Root({ reducer: (_, update) => update, default: () => '', }), - fixes: Annotation({ + currentRisks: Annotation({ reducer: (_, update) => update, default: () => [], }), + currentComplexity: Annotation({ + reducer: (_, update) => update, + default: () => 1, + }), // Quality metrics clarityScore: Annotation({ reducer: (_, update) => update, @@ -94056,26 +90212,23 @@ const PRAgentState = Annotation.Root({ reducer: (current, update) => current + update, default: () => 0, }), - // Semgrep static analysis - semgrepResult: Annotation({ - reducer: (_, update) => update, - default: () => null, - }), - semgrepSummary: Annotation({ - reducer: (_, update) => update, - default: () => null, - }), }); /** * Base class for PR agents with self-refinement workflow */ class BasePRAgentWorkflow { - model; - workflow; + model; // Now optional! + mode; + workflow; // Optional in PROMPT_ONLY mode checkpointer = new MemorySaver(); tools; - constructor(model) { + constructor(mode = ExecutionMode.EXECUTE, model) { + this.mode = mode; this.model = model; + // Validation: LLM required in EXECUTE mode + if (mode === ExecutionMode.EXECUTE && !model) { + throw new Error('BasePRAgentWorkflow: LLM is required when mode is EXECUTE'); + } // Initialize tools this.tools = [ createFileAnalyzerTool(), @@ -94083,45 +90236,248 @@ class BasePRAgentWorkflow { createComplexityScorerTool(), createSummaryGeneratorTool(), ]; - this.workflow = this.buildWorkflow(); + // Only build workflow in EXECUTE mode + if (mode === ExecutionMode.EXECUTE) { + this.workflow = this.buildWorkflow(); + } } /** * Build the PR analysis workflow */ buildWorkflow() { const graph = new StateGraph(PRAgentState); - // Define nodes - simplified workflow + // Define nodes graph.addNode('analyzeFiles', this.analyzeFilesNode.bind(this)); - graph.addNode('runStaticAnalysis', this.runStaticAnalysisNode.bind(this)); - graph.addNode('generateFixes', this.generateFixesNode.bind(this)); + graph.addNode('detectRisks', this.detectRisksNode.bind(this)); + graph.addNode('calculateComplexity', this.calculateComplexityNode.bind(this)); graph.addNode('generateSummary', this.generateSummaryNode.bind(this)); + graph.addNode('evaluateQuality', this.evaluateQualityNode.bind(this)); + graph.addNode('refineAnalysis', this.refineAnalysisNode.bind(this)); graph.addNode('finalize', this.finalizeNode.bind(this)); // Set entry point const entryPoint = 'analyzeFiles'; graph.setEntryPoint(entryPoint); - // Build simplified linear workflow graph - graph.addEdge(entryPoint, 'runStaticAnalysis'); - graph.addEdge('runStaticAnalysis', 'generateFixes'); - graph.addEdge('generateFixes', 'generateSummary'); - graph.addEdge('generateSummary', 'finalize'); + // Build workflow graph + graph.addEdge(entryPoint, 'detectRisks'); + graph.addEdge('detectRisks', 'calculateComplexity'); + graph.addEdge('calculateComplexity', 'generateSummary'); + graph.addEdge('generateSummary', 'evaluateQuality'); + // Conditional: refine or finalize + graph.addConditionalEdges('evaluateQuality', this.shouldRefine.bind(this), { + refine: 'refineAnalysis', + finalize: 'finalize', + }); + // After refinement, evaluate again + graph.addEdge('refineAnalysis', 'evaluateQuality'); + // End after finalization graph.addEdge('finalize', END); return graph.compile({ checkpointer: this.checkpointer }); } /** * Execute the agent workflow + * Routes to either EXECUTE mode (run analysis) or PROMPT_ONLY mode (return prompts) */ async execute(context, options) { + if (this.mode === ExecutionMode.PROMPT_ONLY) { + return await this.buildAllPrompts(context); + } + else { + return this.executeAnalysis(context, options); + } + } + /** + * Build all prompts for PROMPT_ONLY mode (without executing them) + * Also runs static analysis tools that don't require an LLM + */ + async buildAllPrompts(context) { + const files = parseDiff(context.diff); + const prompts = []; + // Build arch-docs context if available + let archDocsContext = ''; + if (context.archDocs?.available) { + archDocsContext = formatArchDocsForPrompt(context.archDocs); + } + // === RUN STATIC ANALYSIS (no LLM needed) === + // These features run immediately and results are included in the output + console.log('🔧 Running static analysis tools...'); + const staticAnalysis = await this.detectAndAnalyzeChangeTypes(files, context); + console.log(`✅ Static analysis complete`); + // 1. File Analysis Prompts (for important files) + const filesToAnalyze = files.slice(0, 15); + const importantFiles = filesToAnalyze.filter(f => f.additions + f.deletions > 20 || + f.path.includes('config') || + f.path.includes('schema') || + f.path.includes('migration') || + f.path.includes('test')).slice(0, 5); + if (importantFiles.length > 0) { + prompts.push(this.buildFileAnalysisPrompt(importantFiles, archDocsContext)); + } + // 2. Risk Detection Prompt + prompts.push(this.buildRiskDetectionPrompt(files, archDocsContext, context)); + // 3. Summary Generation Prompt + prompts.push(this.buildSummaryPrompt(files, archDocsContext, context)); + // 4. Self Refinement Prompt (placeholder - would need analysis results) + // Note: This would typically need results from previous steps + // For now, we'll skip it in PROMPT_ONLY mode or make it conditional + return { + mode: 'prompt_only', + context, + prompts, + // Include static analysis results + staticAnalysis, + instructions: `Execute these prompts sequentially using your LLM: +1. First, analyze the important files in the PR +2. Then detect risks and security issues +3. Generate an overall PR summary +4. (Optional) Refine the analysis based on results + +Each prompt includes the necessary context and instructions for execution. + +Note: Static analysis (test suggestions, DevOps costs, coverage reports) has already been run and is included below.` + }; + } + /** + * Build file analysis prompt + */ + buildFileAnalysisPrompt(importantFiles, archDocsContext) { + const prompt = `Analyze these files from a pull request. For EACH file, provide a detailed analysis considering the repository's architecture standards. +${archDocsContext ? '\n' + archDocsContext : ''} + +Files to analyze: +${importantFiles.map(f => ` +File: ${f.path} +Status: ${f.status || 'modified'} +Changes: +${f.additions} -${f.deletions} +Diff preview: +\`\`\` +${f.diff.substring(0, 500)} +\`\`\` +`).join('\n---\n')} + +${archDocsContext ? `CRITICAL INSTRUCTIONS: +- For EACH file, reference the relevant architecture documentation sections above +- Explain how the changes align with or diverge from established patterns +- Identify specific guidelines that apply to each file +- Mention which parts of the architecture are affected +- Compare changes against documented standards + +` : ''} + +Respond with a JSON object mapping file paths to analysis objects: +{ + "path/to/file": { + "summary": "Description that references relevant arch-docs patterns/guidelines", + "risks": ["risk with arch-docs context", "risk2"], + "complexity": 1-5, + "recommendations": ["recommendation based on arch-docs standards"] + } +} + +${archDocsContext ? 'Each summary MUST reference the specific architecture documentation that applies to this file.' : ''}`; + return { + step: 'fileAnalysis', + prompt, + context: { fileCount: importantFiles.length }, + instructions: 'Analyze each file and return JSON object with file analyses' + }; + } + /** + * Build risk detection prompt + */ + buildRiskDetectionPrompt(files, archDocsContext, context) { + const prompt = `Review this pull request for potential risks, security issues, and code quality problems. + +${archDocsContext ? archDocsContext : ''} + +Files changed (${files.length} total): +${files.map(f => `- ${f.path} (+${f.additions}/-${f.deletions})`).join('\n')} + +Full diff: +\`\`\`diff +${context.diff.substring(0, 8000)} +\`\`\` + +${archDocsContext ? `You have access to architecture documentation. Reference relevant security guidelines when identifying risks. + +Return a JSON array of risk objects with archDocsSource and archDocsExcerpt: +[ + { + "file": "path/to/file", + "line": 42, + "comment": "Description of risk", + "severity": "critical|warning|suggestion", + "archDocsSource": "security.md", + "archDocsExcerpt": "Relevant excerpt from arch-docs", + "reason": "Why this is a risk based on arch-docs" + } +] + +DO NOT return simple string arrays. Each risk MUST be an object with archDocsSource, archDocsExcerpt, and reason fields.` : '["risk 1", "risk 2", ...]'} + +Only include risks that are actually present. If no significant risks, return an empty array [].`; + return { + step: 'riskDetection', + prompt, + context: { fileCount: files.length }, + instructions: 'Detect risks and return JSON array of risk objects' + }; + } + /** + * Build summary generation prompt + */ + buildSummaryPrompt(files, archDocsContext, context) { + const prompt = `Generate a comprehensive summary of this pull request. + +${archDocsContext ? archDocsContext : ''} + +PR Title: ${context.title || 'Untitled PR'} + +Files changed: ${files.length} +Total additions: +${files.reduce((sum, f) => sum + f.additions, 0)} +Total deletions: -${files.reduce((sum, f) => sum + f.deletions, 0)} + +Key files: +${files.slice(0, 10).map(f => `- ${f.path} (+${f.additions}/-${f.deletions})`).join('\n')} + +Diff excerpt: +\`\`\`diff +${context.diff.substring(0, 5000)} +\`\`\` + +${archDocsContext ? 'Consider the design patterns and architecture from the repository documentation when analyzing the changes.\n' : ''} + +Provide a detailed, well-structured summary (3-5 paragraphs) that would help a reviewer understand the scope and purpose of this PR.`; + return { + step: 'summaryGeneration', + prompt, + context: {}, + instructions: 'Generate detailed PR summary (3-5 paragraphs)' + }; + } + /** + * Execute the agent workflow in EXECUTE mode (with LLM) + */ + async executeAnalysis(context, options) { + if (!this.workflow) { + throw new Error('Workflow not initialized - executeAnalysis should only be called in EXECUTE mode'); + } const startTime = Date.now(); // Fast path: skip self-refinement if (options?.skipSelfRefinement) { return this.executeFastPath(context, startTime); } + const config = { + maxIterations: 3, + clarityThreshold: 80, + skipSelfRefinement: false, + }; const initialState = { context, iteration: 0, fileAnalyses: new Map(), currentSummary: '', - fixes: [], + currentRisks: [], + currentComplexity: 1, clarityScore: 0, missingInformation: [], recommendations: [], @@ -94129,14 +90485,12 @@ class BasePRAgentWorkflow { reasoning: [], totalInputTokens: 0, totalOutputTokens: 0, - semgrepResult: null, - semgrepSummary: null, - archDocsInfluencedStages: [], - archDocsKeyInsights: [], }; const workflowConfig = { configurable: { thread_id: `pr-agent-${Date.now()}`, + maxIterations: config.maxIterations, + clarityThreshold: config.clarityThreshold, }, recursionLimit: 50, }; @@ -94176,18 +90530,32 @@ class BasePRAgentWorkflow { influencedStages: [...new Set(stateAny.archDocsInfluencedStages || [])], keyInsights: [...new Set(stateAny.archDocsKeyInsights || [])], } : undefined; - // Build static analysis summary - const staticAnalysis = stateAny.semgrepSummary ? { - enabled: true, - totalFindings: stateAny.semgrepSummary.totalFindings, - errorCount: stateAny.semgrepSummary.errorCount, - warningCount: stateAny.semgrepSummary.warningCount, - criticalIssues: stateAny.semgrepSummary.criticalFindings.map((f) => f.extra.message).slice(0, 5), - } : undefined; + // Smart change detection - only include relevant outputs + const files = parseDiff(context.diff); + const enhancedResult = await this.detectAndAnalyzeChangeTypes(files, context); + // Convert currentRisks to fixes format for backward compatibility + const fixes = finalState.currentRisks.map((risk) => { + // Risk can be a string or RiskItem object + if (typeof risk === 'string') { + return { + file: '', + comment: risk, + severity: 'warning', + }; + } + return { + file: risk.file || '', + line: risk.line, + comment: risk.description || risk.reason || String(risk), + severity: risk.severity || 'warning', + }; + }); return { summary: finalState.currentSummary, fileAnalyses: finalState.fileAnalyses, - fixes: finalState.fixes, + fixes, + overallComplexity: finalState.currentComplexity, + overallRisks: finalState.currentRisks, recommendations: finalState.recommendations, insights: finalState.insights, reasoning: finalState.reasoning, @@ -94197,7 +90565,8 @@ class BasePRAgentWorkflow { executionTime, mode: context.mode, archDocsImpact, - staticAnalysis, + // Conditionally include new features based on change types + ...enhancedResult, }; } /** @@ -94210,7 +90579,8 @@ class BasePRAgentWorkflow { iteration: 0, fileAnalyses: new Map(), currentSummary: '', - fixes: [], + currentRisks: [], + currentComplexity: 1, clarityScore: 0, missingInformation: [], recommendations: [], @@ -94218,21 +90588,21 @@ class BasePRAgentWorkflow { reasoning: [], totalInputTokens: 0, totalOutputTokens: 0, - semgrepResult: null, - semgrepSummary: null, }; // Execute workflow nodes sequentially (skip refinement loop) let state = initialState; try { // 1. Analyze files state = await this.analyzeFilesNode(state); - // 2. Run static analysis - state = await this.runStaticAnalysisNode(state); - // 3. Generate fixes - state = await this.generateFixesNode(state); + // 2. Detect risks + state = await this.detectRisksNode(state); + // 3. Calculate complexity + state = await this.calculateComplexityNode(state); // 4. Generate summary state = await this.generateSummaryNode(state); - // 5. Finalize (includes recommendations) + // 5. Generate recommendations (skip quality evaluation) + state = await this.refineAnalysisNode(state); + // 6. Finalize state = await this.finalizeNode(state); const executionTime = Date.now() - startTime; // Build arch-docs impact summary with deduplication @@ -94244,18 +90614,32 @@ class BasePRAgentWorkflow { influencedStages: [...new Set(stateAny.archDocsInfluencedStages || [])], keyInsights: [...new Set(stateAny.archDocsKeyInsights || [])], } : undefined; - // Build static analysis summary - const staticAnalysis = state.semgrepSummary ? { - enabled: true, - totalFindings: state.semgrepSummary.totalFindings, - errorCount: state.semgrepSummary.errorCount, - warningCount: state.semgrepSummary.warningCount, - criticalIssues: state.semgrepSummary.criticalFindings.map((f) => f.extra.message).slice(0, 5), - } : undefined; + // Smart change detection - only include relevant outputs + const files = parseDiff(context.diff); + const enhancedResult = await this.detectAndAnalyzeChangeTypes(files, context); + // Convert currentRisks to fixes format for backward compatibility + const fixes = state.currentRisks.map((risk) => { + // Risk can be a string or RiskItem object + if (typeof risk === 'string') { + return { + file: '', + comment: risk, + severity: 'warning', + }; + } + return { + file: risk.file || '', + line: risk.line, + comment: risk.description || risk.reason || String(risk), + severity: risk.severity || 'warning', + }; + }); return { summary: state.currentSummary, fileAnalyses: state.fileAnalyses, - fixes: state.fixes, + fixes, + overallComplexity: state.currentComplexity, + overallRisks: state.currentRisks, recommendations: state.recommendations, insights: state.insights, reasoning: [...state.reasoning, 'Fast path: Self-refinement evaluation skipped for speed'], @@ -94265,7 +90649,8 @@ class BasePRAgentWorkflow { executionTime, mode: context.mode, archDocsImpact, - staticAnalysis, + // Conditionally include new features based on change types + ...enhancedResult, }; } catch (error) { @@ -94273,6 +90658,118 @@ class BasePRAgentWorkflow { throw error; } } + /** + * Smart change detection - analyzes files and returns only relevant enhanced features + */ + async detectAndAnalyzeChangeTypes(files, context) { + const result = {}; + // === PROJECT CLASSIFICATION === + // Check DB cache first, only run classification if not cached (saves tokens) + const repoOwner = context.config?.repoOwner || 'local'; + const repoName = context.config?.repoName || 'unknown'; + let cachedClassification = getProjectClassification(repoOwner, repoName); + if (cachedClassification) { + // Use cached classification + result.projectClassification = cachedClassification; + } + else { + // Run classification and store for caching + const classification = classifyProject(files.map(f => ({ filename: f.path, patch: f.diff }))); + result.projectClassification = formatClassification(classification); + } + // Categorize files by type + const codeFiles = files.filter(f => isCodeFile(f.path) && !isTestFile(f.path)); + const testFiles = files.filter(f => isTestFile(f.path)); + const devOpsFiles = files.filter(f => isDevOpsFile(f.path).isDevOps); + console.log(`📊 Change Analysis: ${codeFiles.length} code files, ${testFiles.length} test files, ${devOpsFiles.length} DevOps files`); + // 1. Developer changes without tests → Test Suggestions + if (codeFiles.length > 0 && codeFiles.length > testFiles.length) { + console.log(`🧪 Detecting test suggestions for ${codeFiles.length} code files...`); + const frameworkInfo = detectTestFramework(context.config?.repoPath || '.'); + const testSuggestions = []; + for (const file of codeFiles) { + // Check if there's a corresponding test file in the PR + const baseName = file.path.replace(/\.[^/.]+$/, '').split('/').pop() || ''; + const hasTest = testFiles.some(t => t.path.toLowerCase().includes(baseName.toLowerCase())); + if (!hasTest && file.additions > 5) { + // Extract function names from diff for better test generation + const functionMatches = file.diff.match(/(?:function|const|let|var|async)\s+(\w+)/g) || []; + const functionNames = functionMatches + .map(m => m.replace(/(?:function|const|let|var|async)\s+/, '')) + .filter(name => name.length > 2 && !['the', 'and', 'for'].includes(name)); + const testCode = generateTestTemplate(frameworkInfo.framework, file.path, file.diff, functionNames.slice(0, 5)); + testSuggestions.push({ + forFile: file.path, + testFramework: frameworkInfo.framework, + testCode, + description: `Suggested tests for new/modified code in ${file.path}`, + testFilePath: suggestTestFilePath(file.path, frameworkInfo.framework), + }); + } + } + if (testSuggestions.length > 0) { + result.testSuggestions = testSuggestions; + console.log(`✅ Generated ${testSuggestions.length} test suggestions`); + } + } + // 1b. Existing tests → Test Enhancement Suggestions + if (testFiles.length > 0 && codeFiles.length > 0) { + console.log(`🔬 Analyzing ${testFiles.length} existing test file(s) for improvements...`); + const frameworkInfo = detectTestFramework(context.config?.repoPath || '.'); + for (const testFile of testFiles) { + // Find corresponding source file + const baseName = testFile.path + .replace(/\.(test|spec)\./i, '.') + .replace(/^(test|tests|__tests__)\//i, '') + .replace(/\/(test|tests|__tests__)\//i, '/'); + const sourceFile = codeFiles.find(f => f.path.includes(baseName.split('/').pop()?.replace(/\.[^.]+$/, '') || '')); + if (sourceFile && testFile.additions > 0) { + // Analyze test quality and suggest enhancements + const enhancement = analyzeTestQuality({ path: testFile.path, diff: testFile.diff }, { path: sourceFile.path, diff: sourceFile.diff }, frameworkInfo.framework); + if (enhancement.suggestions.length > 0) { + // Add as test suggestion with enhancement flag + result.testSuggestions = result.testSuggestions || []; + result.testSuggestions.push({ + forFile: sourceFile.path, + testFramework: frameworkInfo.framework, + testCode: enhancement.enhancementCode || '', + description: `Test enhancements for ${external_path_default().basename(testFile.path)}: ${enhancement.suggestions.join(', ')}`, + testFilePath: testFile.path, + isEnhancement: true, + existingTestFile: testFile.path, + }); + console.log(` → Found ${enhancement.missingScenarios.length} missing scenario(s) in ${external_path_default().basename(testFile.path)}`); + } + } + } + const enhancementCount = result.testSuggestions?.filter(s => s.isEnhancement).length || 0; + if (enhancementCount > 0) { + console.log(`✅ Generated ${enhancementCount} test enhancement suggestion(s)`); + } + } + // 2. DevOps/IaC changes → Cost Estimation + if (devOpsFiles.length > 0) { + console.log(`💰 Analyzing DevOps costs for ${devOpsFiles.length} files...`); + const costAnalysis = analyzeDevOpsFiles(devOpsFiles); + if (costAnalysis.hasDevOpsChanges && costAnalysis.estimates.length > 0) { + result.devOpsCostEstimates = costAnalysis.estimates; + console.log(`✅ Estimated costs for ${costAnalysis.estimates.length} resources (~$${costAnalysis.totalEstimatedCost.toFixed(2)}/month)`); + } + } + // 3. Test/QA changes → Coverage Report (only if configured) + if (testFiles.length > 0 || codeFiles.length > 0) { + const coverageConfig = detectCoverageTool(context.config?.repoPath || '.'); + if (coverageConfig.configured) { + console.log(`📊 Checking coverage (${coverageConfig.tool} detected)...`); + const coverage = readCoverageReport(context.config?.repoPath || '.'); + if (coverage.available) { + result.coverageReport = coverage; + console.log(`✅ Coverage: ${coverage.overallPercentage?.toFixed(1)}%`); + } + } + } + return result; + } // Workflow nodes async analyzeFilesNode(state) { const { context } = state; @@ -94298,6 +90795,9 @@ class BasePRAgentWorkflow { // Get detailed analysis for important files if (importantFiles.length > 0) { try { + if (!this.model) { + throw new Error('LLM is required for file analysis in EXECUTE mode'); + } const fileDetailsPrompt = `Analyze these files from a pull request. For EACH file, provide a detailed analysis considering the repository's architecture standards. ${archDocsContext ? '\n' + archDocsContext : ''} @@ -94409,209 +90909,213 @@ ${archDocsContext ? 'Each summary MUST reference the specific architecture docum archDocsKeyInsights: archDocsInsights, }; } - async runStaticAnalysisNode(state) { - const { context } = state; - // Skip if static analysis is disabled - if (!context.enableStaticAnalysis) { - console.log('⏭️ Static analysis disabled, skipping...'); - return state; - } - try { - // Get current working directory for analysis - const targetPath = process.cwd(); - // Run Semgrep analysis - const semgrepResult = await runSemgrepAnalysis(targetPath, { - enabled: true, - timeout: 30, - maxFileSize: 1000000, // 1MB - excludePaths: [ - '**/node_modules/**', - '**/dist/**', - '**/build/**', - '**/.git/**', - '**/*.min.js', - '**/*.map', - ], - }, context.language, context.framework); - // Check for errors - if (semgrepResult.errors && semgrepResult.errors.length > 0) { - const hasBlockingError = semgrepResult.errors.some(e => e.level === 'error' && e.type === 'semgrep_not_installed'); - if (hasBlockingError) { - console.log('ℹ️ Semgrep not available, continuing without static analysis'); - return state; - } - } - // Filter findings to only include changed files - const changedFilePaths = context.files.map(f => f.path); - const relevantFindings = filterFindingsByChangedFiles(semgrepResult.results || [], changedFilePaths); - // Create filtered result - const filteredResult = { - ...semgrepResult, - results: relevantFindings, - }; - // Summarize findings - const summary = summarizeSemgrepFindings(filteredResult); - console.log(` Found ${summary.totalFindings} issues (${summary.errorCount} errors, ${summary.warningCount} warnings)`); - return { - ...state, - semgrepResult: filteredResult, - semgrepSummary: summary, - insights: [`Static analysis: ${summary.totalFindings} findings in changed files`], - }; - } - catch (error) { - console.error('Error running static analysis:', error); - return { - ...state, - insights: ['Static analysis encountered an error and was skipped'], - }; - } - } - async generateFixesNode(state) { - const { context, fileAnalyses, semgrepSummary, semgrepResult } = state; - console.log('🔧 Generating fixes...'); - // If static analysis is enabled, convert Semgrep findings to fixes - if (context.enableStaticAnalysis && semgrepResult && semgrepSummary && semgrepSummary.totalFindings > 0) { - console.log(' Converting Semgrep findings to fixes'); - const fixes = semgrepResult.results.map((finding) => ({ - file: finding.path, - line: finding.start.line, - comment: `${finding.extra.severity === 'ERROR' ? '🔴 **Critical**: ' : finding.extra.severity === 'WARNING' ? '🟡 **Warning**: ' : 'ℹ️ '}${finding.extra.message}\n\n**Rule**: ${finding.check_id}${finding.extra.metadata?.cwe ? `\n**CWE**: ${finding.extra.metadata.cwe.join(', ')}` : ''}${finding.extra.metadata?.owasp ? `\n**OWASP**: ${finding.extra.metadata.owasp.join(', ')}` : ''}`, - severity: finding.extra.severity === 'ERROR' ? 'critical' : finding.extra.severity === 'WARNING' ? 'warning' : 'suggestion', - source: 'semgrep', - })); - return { - ...state, - fixes, - insights: [`Generated ${fixes.length} fixes from Semgrep findings`], - }; - } - // Otherwise, do AI-based fix generation - console.log(' Running AI-based fix generation'); - // Parse diff to get file paths and line numbers - const files = parseDiff(context.diff); + async detectRisksNode(state) { + const { context, fileAnalyses } = state; + console.log('⚠️ Detecting risks...'); + // Build context for risk analysis const fileList = Array.from(fileAnalyses.entries()) .slice(0, 15) .map(([path, analysis]) => `${path} (+${analysis.changes.additions} -${analysis.changes.deletions})`) .join('\n'); - // Get diff sample with line numbers - const diffSample = context.diff.substring(0, 12000); + // Get a sample of the diff for risk analysis (limit size) + const diffSample = context.diff.substring(0, 8000); // First 8KB for context // Add security context from arch-docs if available let securityContext = ''; let allDocs = []; + let securityDoc = null; + let patternsDoc = null; if (context.archDocs?.available) { allDocs = parseAllArchDocs(); const secDoc = getSecurityContext(allDocs); if (secDoc) { securityContext = `\n## Security Guidelines from Repository Documentation\n\n${secDoc.substring(0, 3000)}\n`; + securityDoc = allDocs.find(d => d.filename === 'security'); } + // Also get patterns that might indicate risks const patterns = getPatternsContext(allDocs); if (patterns) { securityContext += `\n## Repository Patterns and Best Practices\n\n${patterns.substring(0, 2000)}\n`; + patternsDoc = allDocs.find(d => d.filename === 'patterns'); } } - const fixesPrompt = `You are a code reviewer analyzing a pull request. Generate CRUCIAL, actionable fixes as PR comments. + const riskPrompt = `You are a security and code quality expert analyzing a pull request for potential risks. ${securityContext} -Analyze the following changes and identify issues that NEED to be fixed. Focus on: -1. **Security Issues**: Exposed credentials, insecure patterns, authentication/authorization problems -2. **Critical Bugs**: Logic errors, null pointer risks, race conditions -3. **Breaking Changes**: API changes without versioning, removed functionality -4. **Code Quality**: Missing error handling, code smells, anti-patterns -5. **Performance**: Inefficient algorithms, memory leaks, N+1 queries +Analyze the following changes and identify SPECIFIC risks in these categories: +1. **Security Risks**: Exposed credentials, insecure patterns, authentication/authorization issues +2. **Breaking Changes**: API changes, database schema changes, removed functionality +3. **Performance Concerns**: Inefficient algorithms, memory leaks, N+1 queries +4. **Code Quality**: Complex logic, missing error handling, lack of tests +5. **Operational Risks**: Configuration changes, deployment concerns, dependency updates PR Title: ${context.title || 'No title provided'} Files changed: ${fileList} -Diff: +Diff sample: \`\`\` ${diffSample} \`\`\` -${securityContext ? `IMPORTANT: Reference repository documentation when applicable.` : ''} +${securityContext ? `CRITICAL INSTRUCTIONS: +- You MUST reference the repository documentation guidelines above when identifying each risk +- For EVERY risk you identify, find the relevant guideline from the documentation +- Explain HOW the code change violates or conflicts with the documented standards +- Quote the specific guideline that makes this a risk +- Be specific about why this matters based on the repository's own standards -For EACH issue found, provide: -- **file**: The file path where the issue exists -- **line**: Approximate line number (if you can identify it from the diff, otherwise omit) -- **comment**: Actionable PR comment explaining the issue and how to fix it. Be specific and helpful. -- **severity**: "critical" (must fix), "warning" (should fix), or "suggestion" (nice to have) +Example format for a risk with documentation: +{ + "description": "File exceeds maximum line count recommended for maintainability", + "archDocsSource": "code-quality.md", + "archDocsExcerpt": "Keep individual files under 500 lines to maintain testability and readability", + "reason": "This file contains 990 lines, nearly 2x the repository standard, which increases maintenance burden and makes comprehensive testing more difficult" +} +` : ''} -Return a JSON array of fix objects: -[ - { - "file": "src/path/to/file.ts", - "line": 42, - "comment": "**Security Issue**: Hardcoded API key detected. Use environment variables instead.\n\n**Fix**: Move to process.env.API_KEY or use a secrets manager.", - "severity": "critical" - }, +Provide a JSON array of risk objects. Each risk MUST include: +- description: Clear, specific description of the risk +${securityContext ? `- archDocsSource: REQUIRED - Which documentation file from above this relates to (e.g., "security.md", "patterns.md", "code-quality.md") +- archDocsExcerpt: REQUIRED - Direct quote from the repository documentation that this violates +- reason: REQUIRED - Detailed explanation of why this is a risk based on the specific guideline quoted above +` : ''} + +Format: +${securityContext ? `[ { - "file": "src/utils/helper.ts", - "comment": "**Missing Error Handling**: This function can throw but errors aren't caught.\n\n**Fix**: Wrap in try-catch or add error handling.", - "severity": "warning" + "description": "Specific risk description", + "archDocsSource": "documentation-file.md", + "archDocsExcerpt": "Exact quote from the documentation", + "reason": "Detailed explanation connecting the code change to the guideline violation" } ] -Only include CRUCIAL fixes that matter. If no significant issues, return an empty array [].`; +DO NOT return simple string arrays. Each risk MUST be an object with archDocsSource, archDocsExcerpt, and reason fields.` : '["risk 1", "risk 2", ...]'} + +Only include risks that are actually present. If no significant risks, return an empty array [].`; try { - const response = await this.model.invoke(fixesPrompt); + if (!this.model) { + throw new Error('LLM is required for risk detection in EXECUTE mode'); + } + const response = await this.model.invoke(riskPrompt); const content = response.content; // Track tokens const usage = response.response_metadata?.usage; const inputTokens = usage?.input_tokens || 0; const outputTokens = usage?.output_tokens || 0; // Parse JSON response - let fixes = []; + let risks = []; + let hasArchDocsEnhancement = false; try { // Extract JSON from markdown code blocks if present const jsonMatch = content.match(/\[[\s\S]*\]/); if (jsonMatch) { - const parsedFixes = JSON.parse(jsonMatch[0]); - fixes = parsedFixes - .filter((f) => f.file && f.comment) - .map((f) => ({ - file: f.file, - line: f.line, - comment: f.comment, - severity: f.severity || 'warning', - source: 'ai', - })) - // Prioritize critical and warning fixes, limit suggestions - .sort((a, b) => { - const severityOrder = { critical: 0, warning: 1, suggestion: 2 }; - const aSeverity = a.severity || 'warning'; - const bSeverity = b.severity || 'warning'; - return (severityOrder[aSeverity] ?? 2) - (severityOrder[bSeverity] ?? 2); - }) - // Limit to top 10 fixes (prioritize critical/warning) - .slice(0, 10); + const parsedRisks = JSON.parse(jsonMatch[0]); + // Check if risks have arch-docs references + if (parsedRisks.length > 0 && typeof parsedRisks[0] === 'object' && 'archDocsSource' in parsedRisks[0]) { + // Transform to our RiskItem format + risks = parsedRisks.map((r) => ({ + description: r.description, + archDocsReference: r.archDocsSource ? { + source: r.archDocsSource, + excerpt: r.archDocsExcerpt || '', + reason: r.reason || '', + } : undefined, + })); + hasArchDocsEnhancement = true; + } + else if (parsedRisks.length > 0 && typeof parsedRisks[0] === 'string') { + // Legacy format - just strings + risks = parsedRisks; + } + else { + risks = parsedRisks; + } } } catch (parseError) { - console.warn('Failed to parse fixes JSON:', parseError); + console.warn('Failed to parse risk JSON, extracting manually'); + // Fallback: extract bullet points as strings + const lines = content.split('\n'); + risks = lines + .filter(line => line.trim().startsWith('-') || line.trim().startsWith('•')) + .map(line => line.replace(/^[-•]\s*/, '').trim()) + .filter(line => line.length > 0); } - // Add pattern-based fixes for critical issues + // Add basic pattern-based checks with arch-docs enhancement + const patternRisks = []; if (context.diff.includes('password') || context.diff.includes('secret') || context.diff.includes('api_key')) { - const fileMatch = context.diff.match(/^diff --git a\/.*? b\/(.+)$/m); - const affectedFile = fileMatch ? fileMatch[1] : 'unknown'; - fixes.push({ - file: affectedFile, - comment: '**Security Issue**: Potential hardcoded credentials detected. Use environment variables or a secrets manager instead of hardcoding sensitive values.', - severity: 'critical', - source: 'ai', - }); + const riskDesc = 'Potential credentials or sensitive data in code changes'; + if (securityDoc) { + // Always enhance with arch-docs if available + patternRisks.push({ + description: riskDesc, + archDocsReference: { + source: 'security.md', + excerpt: 'Never commit credentials, API keys, or secrets to the repository. Use environment variables for all sensitive configuration.', + reason: 'Code changes contain keywords like "password", "secret", or "api_key" which may indicate hardcoded credentials. This violates the repository security policy requiring all secrets to be externalized via environment variables.', + }, + }); + } + else { + patternRisks.push(riskDesc); + } + } + if (fileAnalyses.size > 20) { + const qualityDoc = allDocs.find(d => d.filename === 'code-quality'); + if (qualityDoc && securityContext) { + patternRisks.push({ + description: `Large change set (${fileAnalyses.size} files) increases review complexity and error risk`, + archDocsReference: { + source: 'code-quality.md', + excerpt: 'Keep pull requests focused and under 15 files when possible for thorough review', + reason: `This PR modifies ${fileAnalyses.size} files, exceeding the recommended limit. Large PRs are harder to review thoroughly and increase the likelihood of missing critical issues.`, + }, + }); + } + else { + patternRisks.push(`Large change set (${fileAnalyses.size} files) - may be difficult to review thoroughly`); + } } - // Track arch-docs usage - const archDocsStages = securityContext ? ['fix-generation'] : []; + if (context.diff.includes('DROP TABLE') || context.diff.includes('ALTER TABLE')) { + if (securityContext) { + patternRisks.push({ + description: 'Database schema changes detected - requires careful migration planning', + archDocsReference: { + source: 'patterns.md', + excerpt: 'All database schema changes must be backwards-compatible and include rollback procedures', + reason: 'The changes include database schema modifications (DROP TABLE or ALTER TABLE) which can cause data loss or application downtime if not properly planned and tested.', + }, + }); + } + else { + patternRisks.push('Database schema changes detected - requires careful migration planning'); + } + } + // Merge risks, avoiding duplicates (for string risks) + let allRisks; + if (hasArchDocsEnhancement) { + // Keep structured risks + allRisks = [...risks, ...patternRisks]; + } + else { + // Deduplicate string risks + allRisks = [...new Set([...risks, ...patternRisks])]; + } + // Track arch-docs usage in risk detection + const archDocsStages = securityContext ? ['risk-detection'] : []; const archDocsInsights = []; - if (securityContext && context.archDocs?.available && fixes.length > 0) { - archDocsInsights.push(`Generated ${fixes.length} fixes based on repository guidelines`); + if (securityContext && context.archDocs?.available) { + const enhancedCount = allRisks.filter(r => typeof r === 'object' && r.archDocsReference).length; + if (enhancedCount > 0) { + archDocsInsights.push(`Linked ${enhancedCount} risks to specific repository security guidelines and best practices`); + } } return { ...state, - fixes, - insights: [`Generated ${fixes.length} crucial fixes`], + currentRisks: allRisks, + insights: [`Identified ${allRisks.length} potential risks`], totalInputTokens: (state.totalInputTokens || 0) + inputTokens, totalOutputTokens: (state.totalOutputTokens || 0) + outputTokens, archDocsInfluencedStages: archDocsStages, @@ -94619,16 +91123,49 @@ Only include CRUCIAL fixes that matter. If no significant issues, return an empt }; } catch (error) { - console.error('Error generating fixes:', error); + console.error('Error in risk detection:', error); + // Fallback to basic pattern matching + const basicRisks = []; + if (context.diff.includes('password') || context.diff.includes('secret')) { + basicRisks.push('Potential credentials in diff'); + } + if (fileAnalyses.size > 15) { + basicRisks.push('Large change set - difficult to review'); + } return { ...state, - fixes: [], - insights: ['Fix generation encountered an error'], + currentRisks: basicRisks, + insights: [`Identified ${basicRisks.length} potential risks (basic analysis)`], }; } } + async calculateComplexityNode(state) { + const { fileAnalyses, context } = state; + console.log('📊 Calculating complexity...'); + const complexities = Array.from(fileAnalyses.values()).map(f => f.complexity); + const avgComplexity = complexities.length > 0 + ? complexities.reduce((a, b) => a + b, 0) / complexities.length + : 1; + // Track arch-docs influence on complexity + const archDocsStages = context.archDocs?.available ? ['complexity-calculation'] : []; + const archDocsInsights = []; + if (context.archDocs?.available) { + // Check if patterns documentation helped understand complexity + const allDocs = parseAllArchDocs(); + const patterns = getPatternsContext(allDocs); + if (patterns) { + archDocsInsights.push(`Evaluated complexity against repository design patterns and coding standards`); + } + } + return { + ...state, + currentComplexity: Math.round(avgComplexity), + archDocsInfluencedStages: archDocsStages, + archDocsKeyInsights: archDocsInsights, + }; + } async generateSummaryNode(state) { - const { context, fileAnalyses, fixes, semgrepSummary } = state; + const { context, fileAnalyses, currentRisks, currentComplexity } = state; console.log('📝 Generating detailed summary...'); const totalFiles = fileAnalyses.size; const totalAdditions = Array.from(fileAnalyses.values()).reduce((sum, f) => sum + f.changes.additions, 0); @@ -94636,7 +91173,7 @@ Only include CRUCIAL fixes that matter. If no significant issues, return an empt // Build file list with changes const fileList = Array.from(fileAnalyses.entries()) .slice(0, 20) - .map(([path, analysis]) => `- ${path}: +${analysis.changes.additions} -${analysis.changes.deletions}`) + .map(([path, analysis]) => `- ${path}: +${analysis.changes.additions} -${analysis.changes.deletions} (complexity: ${analysis.complexity}/5)`) .join('\n'); // Add patterns context from arch-docs if available let patternsContext = ''; @@ -94647,36 +91184,37 @@ Only include CRUCIAL fixes that matter. If no significant issues, return an empt patternsContext = `\n## Design Patterns from Repository Documentation\n\n${patterns.substring(0, 2000)}\n`; } } - // Add Semgrep summary if available - let semgrepSummaryContext = ''; - if (semgrepSummary && semgrepSummary.totalFindings > 0) { - semgrepSummaryContext = `\n## Static Analysis Summary (Semgrep)\n\n`; - semgrepSummaryContext += `- Total findings: ${semgrepSummary.totalFindings}\n`; - semgrepSummaryContext += `- Errors: ${semgrepSummary.errorCount}\n`; - semgrepSummaryContext += `- Warnings: ${semgrepSummary.warningCount}\n`; - semgrepSummaryContext += `- Categories affected: ${semgrepSummary.categoriesAffected.join(', ')}\n`; - semgrepSummaryContext += `- Files with issues: ${semgrepSummary.filesWithIssues.length}\n\n`; - } - // Create concise prompt for quick reading - const summaryPrompt = `Analyze this pull request and provide a BRIEF, scannable summary (2-3 sentences max). + // Create comprehensive prompt for LLM + const summaryPrompt = `You are analyzing a pull request. Provide a DETAILED and COMPREHENSIVE summary that covers: -Focus on: -- **What**: What does this PR do? (one sentence) -- **Why**: What problem does it solve or what feature does it add? (one sentence) -- **Impact**: What parts of the codebase are affected? (one sentence if significant) +1. **Overall Purpose**: What is this PR trying to accomplish? What problem does it solve? +2. **Key Changes**: What are the main changes being made? Group related changes together. +3. **Impact Analysis**: What parts of the system are affected? What are the implications? +4. **Technical Details**: Mention important technical aspects (new dependencies, API changes, data model changes, etc.) +5. **Patterns Observed**: Any design patterns, refactoring, or architectural changes? +${patternsContext} PR Title: ${context.title || 'No title provided'} -${context.language ? `Language: ${context.language}${context.framework ? ` (${context.framework})` : ''}` : ''} -Stats: ${totalFiles} files, +${totalAdditions}/-${totalDeletions} lines${fixes.length > 0 ? `, ${fixes.filter((f) => f.severity === 'critical').length} critical fixes` : ''} +Statistics: +- Files changed: ${totalFiles} +- Lines added: ${totalAdditions} +- Lines deleted: ${totalDeletions} +- Overall complexity: ${currentComplexity}/5 +- Risks identified: ${currentRisks.length} -Key files: -${fileList.split('\n').slice(0, 5).join('\n')} +Files changed: +${fileList} + +${currentRisks.length > 0 ? `\nRisks detected:\n${currentRisks.map(r => `- ${r}`).join('\n')}` : ''} -${semgrepSummaryContext && semgrepSummary ? `Static analysis found ${semgrepSummary.totalFindings} issues (${semgrepSummary.errorCount} critical). ` : ''} +${patternsContext ? 'Consider the design patterns and architecture from the repository documentation when analyzing the changes.\n' : ''} -Write a concise summary that helps reviewers quickly understand the PR's purpose and scope. Be direct and specific.`; +Provide a detailed, well-structured summary (3-5 paragraphs) that would help a reviewer understand the scope and purpose of this PR.`; try { + if (!this.model) { + throw new Error('LLM is required for summary generation in EXECUTE mode'); + } const response = await this.model.invoke(summaryPrompt); const detailedSummary = response.content; // Track token usage @@ -94689,9 +91227,6 @@ Write a concise summary that helps reviewers quickly understand the PR's purpose if (patternsContext && context.archDocs?.available) { archDocsInsights.push(`Generated summary aligned with repository architecture and established patterns`); } - if (semgrepSummary && semgrepSummary.totalFindings > 0) { - archDocsInsights.push(`Incorporated ${semgrepSummary.totalFindings} static analysis findings into summary`); - } return { ...state, currentSummary: detailedSummary, @@ -94708,7 +91243,8 @@ Write a concise summary that helps reviewers quickly understand the PR's purpose - Files changed: ${totalFiles} - Additions: ${totalAdditions} - Deletions: ${totalDeletions} -- Fixes identified: ${fixes.length} +- Overall complexity: ${currentComplexity}/5 +- Risks identified: ${currentRisks.length} ${context.title ? `Title: ${context.title}` : ''}`; return { @@ -94717,10 +91253,21 @@ ${context.title ? `Title: ${context.title}` : ''}`; }; } } - async finalizeNode(state) { - const { currentSummary, fixes, fileAnalyses, context } = state; - console.log('✨ Finalizing analysis and generating recommendations...'); - // Build arch-docs context for recommendations if available + async evaluateQualityNode(state) { + const { iteration } = state; + console.log(`🔍 Evaluating quality (iteration ${iteration + 1})...`); + // Simple quality check + const clarityScore = 85; // Placeholder + return { + ...state, + clarityScore, + iteration: iteration + 1, + }; + } + async refineAnalysisNode(state) { + const { currentSummary, currentRisks, fileAnalyses, context } = state; + console.log('🔄 Refining analysis...'); + // Build arch-docs context for refinement let archDocsRefinementContext = ''; if (context.archDocs?.available) { const allDocs = parseAllArchDocs(); @@ -94734,24 +91281,41 @@ ${context.title ? `Title: ${context.title}` : ''}`; if (qualityDoc) { archDocsRefinementContext += `\n## Code Quality Standards\n\n${qualityDoc.content.substring(0, 2000)}\n`; } + // Get KPI metrics + const kpiDoc = allDocs.find(d => d.filename === 'kpi'); + if (kpiDoc) { + archDocsRefinementContext += `\n## Repository Health KPIs\n\n${kpiDoc.content.substring(0, 1500)}\n`; + } } - // Generate recommendations - const refinementPrompt = `Based on this PR analysis, provide 3-5 specific, actionable recommendations. - ${archDocsRefinementContext} - - PR Summary: - ${currentSummary} - - Fixes Identified: ${fixes.length} - ${fixes.length > 0 ? `\nKey fixes:\n${fixes.slice(0, 5).map(f => `- ${f.file}${f.line ? `:${f.line}` : ''}: ${f.comment.substring(0, 100)}...`).join('\n')}` : ''} - - Files Changed: ${fileAnalyses.size} - - ${archDocsRefinementContext ? 'Use the repository guidelines above to ensure recommendations align with established practices.\n' : ''} - - Provide a JSON array of recommendations: - ["recommendation 1", "recommendation 2", ...]`; + // Generate comprehensive recommendations + const refinementPrompt = `Based on this PR analysis, provide specific, actionable recommendations for the developer and reviewers. +${archDocsRefinementContext} + +PR Summary: +${currentSummary} + +Risks Identified: +${currentRisks.map(r => `- ${r}`).join('\n')} + +Files Changed: ${fileAnalyses.size} + +Consider: +1. Code organization and structure improvements +2. Testing recommendations +3. Documentation needs +4. Performance optimizations +5. Security enhancements +6. Review process suggestions +${archDocsRefinementContext ? '7. Alignment with repository standards and KPIs from arch-docs\n' : ''} + +${archDocsRefinementContext ? 'Use the repository guidelines and standards above to ensure recommendations align with established practices.\n' : ''} + +Provide a JSON array of 3-5 specific, actionable recommendations: +["recommendation 1", "recommendation 2", ...]`; try { + if (!this.model) { + throw new Error('LLM is required for self refinement in EXECUTE mode'); + } const response = await this.model.invoke(refinementPrompt); const content = response.content; // Track tokens @@ -94783,23 +91347,23 @@ ${context.title ? `Title: ${context.title}` : ''}`; 'Consider performance implications of changes', ]; } - // Track arch-docs usage - const archDocsStages = archDocsRefinementContext ? ['finalization'] : []; + // Track arch-docs usage in refinement + const archDocsStages = archDocsRefinementContext ? ['refinement'] : []; const archDocsInsights = []; if (archDocsRefinementContext && context.archDocs?.available) { - archDocsInsights.push(`Generated ${recommendations.length} recommendations based on repository quality standards`); + archDocsInsights.push(`Generated ${recommendations.length} recommendations based on repository quality standards and KPIs`); } return { ...state, recommendations, totalInputTokens: (state.totalInputTokens || 0) + inputTokens, totalOutputTokens: (state.totalOutputTokens || 0) + outputTokens, - archDocsInfluencedStages: [...(state.archDocsInfluencedStages || []), ...archDocsStages], - archDocsKeyInsights: [...(state.archDocsKeyInsights || []), ...archDocsInsights], + archDocsInfluencedStages: archDocsStages, + archDocsKeyInsights: archDocsInsights, }; } catch (error) { - console.error('Error generating recommendations:', error); + console.error('Error refining analysis:', error); return { ...state, recommendations: [ @@ -94810,6 +91374,25 @@ ${context.title ? `Title: ${context.title}` : ''}`; }; } } + async finalizeNode(state) { + console.log('✨ Finalizing analysis...'); + return state; + } + shouldRefine(state) { + // Use defaults if config not accessible + const maxIterations = 3; + const clarityThreshold = 80; + if (state.iteration >= maxIterations) { + console.log(`⏹️ Stopping: Max iterations (${maxIterations}) reached`); + return 'finalize'; + } + if (state.clarityScore >= clarityThreshold) { + console.log(`✅ Stopping: Clarity threshold (${clarityThreshold}) achieved`); + return 'finalize'; + } + console.log(`🔄 Continuing: Iteration ${state.iteration}, clarity ${state.clarityScore}`); + return 'refine'; + } } ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/output_parsers.js @@ -94879,6 +91462,8 @@ function extractToolCalls(content) { //# sourceMappingURL=output_parsers.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/utils/tools.js + + //#region src/utils/tools.ts function handleToolChoice(toolChoice) { if (!toolChoice) return void 0; @@ -94891,6 +91476,29 @@ function handleToolChoice(toolChoice) { }; else return toolChoice; } +const AnthropicToolExtrasSchema = object({ + cache_control: schemas_custom().optional().nullable(), + defer_loading: schemas_boolean().optional(), + input_examples: array(unknown()).optional(), + allowed_callers: array(unknown()).optional() +}); +/** +* Mapping of Anthropic tool types to their required beta feature flags. +* +* This constant defines which beta header is needed for specific tool types +* when making requests to the Anthropic API. Beta features are experimental +* capabilities that may change or be removed. +*/ +const ANTHROPIC_TOOL_BETAS = { + tool_search_tool_regex_20251119: "advanced-tool-use-2025-11-20", + tool_search_tool_bm25_20251119: "advanced-tool-use-2025-11-20", + memory_20250818: "context-management-2025-06-27", + web_fetch_20250910: "web-fetch-2025-09-10", + code_execution_20250825: "code-execution-2025-08-25", + computer_20251124: "computer-use-2025-11-24", + computer_20250124: "computer-use-2025-01-24", + mcp_toolset: "mcp-client-2025-11-20" +}; //#endregion @@ -95583,10 +92191,11 @@ function _makeMessageChunkFromAnthropicEvent(data, fields) { const filteredAdditionalKwargs = {}; for (const [key, value] of Object.entries(additionalKwargs)) if (value !== void 0 && value !== null) filteredAdditionalKwargs[key] = value; const { input_tokens, output_tokens,...rest } = usage ?? {}; + const totalInputTokens = input_tokens + rest.cache_creation_input_tokens + rest.cache_read_input_tokens; const usageMetadata = { - input_tokens, + input_tokens: totalInputTokens, output_tokens, - total_tokens: input_tokens + output_tokens, + total_tokens: totalInputTokens + output_tokens, input_token_details: { cache_creation: rest.cache_creation_input_tokens, cache_read: rest.cache_read_input_tokens @@ -96389,7 +92998,7 @@ const pop = (obj, key) => { const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); //# sourceMappingURL=sleep.mjs.map ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/version.mjs -const VERSION = '0.71.0'; // x-release-please-version +const VERSION = '0.71.2'; // x-release-please-version //# sourceMappingURL=version.mjs.map ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/internal/detect-platform.mjs // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. @@ -97840,7 +94449,7 @@ const createPathTagFunction = (pathEncoder = encodeURIPath) => function path(sta /** * URI-encodes path params and ensures no unsafe /./ or /../ path segments are introduced. */ -const path = /* @__PURE__ */ createPathTagFunction(encodeURIPath); +const path_path = /* @__PURE__ */ createPathTagFunction(encodeURIPath); //# sourceMappingURL=path.mjs.map ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/resources/beta/files.mjs // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. @@ -97884,7 +94493,7 @@ class Files extends APIResource { */ delete(fileID, params = {}, options) { const { betas } = params ?? {}; - return this._client.delete(path `/v1/files/${fileID}`, { + return this._client.delete(path_path `/v1/files/${fileID}`, { ...options, headers: buildHeaders([ { 'anthropic-beta': [...(betas ?? []), 'files-api-2025-04-14'].toString() }, @@ -97907,7 +94516,7 @@ class Files extends APIResource { */ download(fileID, params = {}, options) { const { betas } = params ?? {}; - return this._client.get(path `/v1/files/${fileID}/content`, { + return this._client.get(path_path `/v1/files/${fileID}/content`, { ...options, headers: buildHeaders([ { @@ -97930,7 +94539,7 @@ class Files extends APIResource { */ retrieveMetadata(fileID, params = {}, options) { const { betas } = params ?? {}; - return this._client.get(path `/v1/files/${fileID}`, { + return this._client.get(path_path `/v1/files/${fileID}`, { ...options, headers: buildHeaders([ { 'anthropic-beta': [...(betas ?? []), 'files-api-2025-04-14'].toString() }, @@ -97983,7 +94592,7 @@ class Models extends APIResource { */ retrieve(modelID, params = {}, options) { const { betas } = params ?? {}; - return this._client.get(path `/v1/models/${modelID}?beta=true`, { + return this._client.get(path_path `/v1/models/${modelID}?beta=true`, { ...options, headers: buildHeaders([ { ...(betas?.toString() != null ? { 'anthropic-beta': betas?.toString() } : undefined) }, @@ -98036,43 +94645,57 @@ const MODEL_NONSTREAMING_TOKENS = { //# sourceMappingURL=constants.mjs.map ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/lib/beta-parser.mjs -function maybeParseBetaMessage(message, params) { +function maybeParseBetaMessage(message, params, opts) { if (!params || !('parse' in (params.output_format ?? {}))) { return { ...message, content: message.content.map((block) => { if (block.type === 'text') { - return { - ...block, - parsed: null, - }; + const parsedBlock = Object.defineProperty({ ...block }, 'parsed_output', { + value: null, + enumerable: false, + }); + return Object.defineProperty(parsedBlock, 'parsed', { + get() { + opts.logger.warn('The `parsed` property on `text` blocks is deprecated, please use `parsed_output` instead.'); + return null; + }, + enumerable: false, + }); } return block; }), parsed_output: null, }; } - return parseBetaMessage(message, params); + return parseBetaMessage(message, params, opts); } -function parseBetaMessage(message, params) { - let firstParsed = null; +function parseBetaMessage(message, params, opts) { + let firstParsedOutput = null; const content = message.content.map((block) => { if (block.type === 'text') { - const parsed = parseBetaOutputFormat(params, block.text); - if (firstParsed === null) { - firstParsed = parsed; + const parsedOutput = parseBetaOutputFormat(params, block.text); + if (firstParsedOutput === null) { + firstParsedOutput = parsedOutput; } - return { - ...block, - parsed, - }; + const parsedBlock = Object.defineProperty({ ...block }, 'parsed_output', { + value: parsedOutput, + enumerable: false, + }); + return Object.defineProperty(parsedBlock, 'parsed', { + get() { + opts.logger.warn('The `parsed` property on `text` blocks is deprecated, please use `parsed_output` instead.'); + return parsedOutput; + }, + enumerable: false, + }); } return block; }); return { ...message, content, - parsed_output: firstParsed, + parsed_output: firstParsedOutput, }; } function parseBetaOutputFormat(params, content) { @@ -98321,7 +94944,7 @@ const tokenize = (input) => { //# sourceMappingURL=streaming.mjs.map ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs -var _BetaMessageStream_instances, _BetaMessageStream_currentMessageSnapshot, _BetaMessageStream_params, _BetaMessageStream_connectedPromise, _BetaMessageStream_resolveConnectedPromise, _BetaMessageStream_rejectConnectedPromise, _BetaMessageStream_endPromise, _BetaMessageStream_resolveEndPromise, _BetaMessageStream_rejectEndPromise, _BetaMessageStream_listeners, _BetaMessageStream_ended, _BetaMessageStream_errored, _BetaMessageStream_aborted, _BetaMessageStream_catchingPromiseCreated, _BetaMessageStream_response, _BetaMessageStream_request_id, _BetaMessageStream_getFinalMessage, _BetaMessageStream_getFinalText, _BetaMessageStream_handleError, _BetaMessageStream_beginRequest, _BetaMessageStream_addStreamEvent, _BetaMessageStream_endRequest, _BetaMessageStream_accumulateMessage; +var _BetaMessageStream_instances, _BetaMessageStream_currentMessageSnapshot, _BetaMessageStream_params, _BetaMessageStream_connectedPromise, _BetaMessageStream_resolveConnectedPromise, _BetaMessageStream_rejectConnectedPromise, _BetaMessageStream_endPromise, _BetaMessageStream_resolveEndPromise, _BetaMessageStream_rejectEndPromise, _BetaMessageStream_listeners, _BetaMessageStream_ended, _BetaMessageStream_errored, _BetaMessageStream_aborted, _BetaMessageStream_catchingPromiseCreated, _BetaMessageStream_response, _BetaMessageStream_request_id, _BetaMessageStream_logger, _BetaMessageStream_getFinalMessage, _BetaMessageStream_getFinalText, _BetaMessageStream_handleError, _BetaMessageStream_beginRequest, _BetaMessageStream_addStreamEvent, _BetaMessageStream_endRequest, _BetaMessageStream_accumulateMessage; @@ -98333,7 +94956,7 @@ function tracksToolInput(content) { return content.type === 'tool_use' || content.type === 'server_tool_use' || content.type === 'mcp_tool_use'; } class BetaMessageStream { - constructor(params) { + constructor(params, opts) { _BetaMessageStream_instances.add(this); this.messages = []; this.receivedMessages = []; @@ -98353,6 +94976,7 @@ class BetaMessageStream { _BetaMessageStream_catchingPromiseCreated.set(this, false); _BetaMessageStream_response.set(this, void 0); _BetaMessageStream_request_id.set(this, void 0); + _BetaMessageStream_logger.set(this, void 0); _BetaMessageStream_handleError.set(this, (error) => { __classPrivateFieldSet(this, _BetaMessageStream_errored, true, "f"); if (isAbortError(error)) { @@ -98388,6 +95012,7 @@ class BetaMessageStream { __classPrivateFieldGet(this, _BetaMessageStream_connectedPromise, "f").catch(() => { }); __classPrivateFieldGet(this, _BetaMessageStream_endPromise, "f").catch(() => { }); __classPrivateFieldSet(this, _BetaMessageStream_params, params, "f"); + __classPrivateFieldSet(this, _BetaMessageStream_logger, opts?.logger ?? console, "f"); } get response() { return __classPrivateFieldGet(this, _BetaMessageStream_response, "f"); @@ -98406,6 +95031,7 @@ class BetaMessageStream { * as no `Response` is available. */ async withResponse() { + __classPrivateFieldSet(this, _BetaMessageStream_catchingPromiseCreated, true, "f"); const response = await __classPrivateFieldGet(this, _BetaMessageStream_connectedPromise, "f"); if (!response) { throw new Error('Could not resolve a `Response` object'); @@ -98428,8 +95054,8 @@ class BetaMessageStream { runner._run(() => runner._fromReadableStream(stream)); return runner; } - static createMessage(messages, params, options) { - const runner = new BetaMessageStream(params); + static createMessage(messages, params, options, { logger } = {}) { + const runner = new BetaMessageStream(params, { logger }); for (const message of params.messages) { runner._addMessageParam(message); } @@ -98656,7 +95282,7 @@ class BetaMessageStream { } } } - [(_BetaMessageStream_currentMessageSnapshot = new WeakMap(), _BetaMessageStream_params = new WeakMap(), _BetaMessageStream_connectedPromise = new WeakMap(), _BetaMessageStream_resolveConnectedPromise = new WeakMap(), _BetaMessageStream_rejectConnectedPromise = new WeakMap(), _BetaMessageStream_endPromise = new WeakMap(), _BetaMessageStream_resolveEndPromise = new WeakMap(), _BetaMessageStream_rejectEndPromise = new WeakMap(), _BetaMessageStream_listeners = new WeakMap(), _BetaMessageStream_ended = new WeakMap(), _BetaMessageStream_errored = new WeakMap(), _BetaMessageStream_aborted = new WeakMap(), _BetaMessageStream_catchingPromiseCreated = new WeakMap(), _BetaMessageStream_response = new WeakMap(), _BetaMessageStream_request_id = new WeakMap(), _BetaMessageStream_handleError = new WeakMap(), _BetaMessageStream_instances = new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage() { + [(_BetaMessageStream_currentMessageSnapshot = new WeakMap(), _BetaMessageStream_params = new WeakMap(), _BetaMessageStream_connectedPromise = new WeakMap(), _BetaMessageStream_resolveConnectedPromise = new WeakMap(), _BetaMessageStream_rejectConnectedPromise = new WeakMap(), _BetaMessageStream_endPromise = new WeakMap(), _BetaMessageStream_resolveEndPromise = new WeakMap(), _BetaMessageStream_rejectEndPromise = new WeakMap(), _BetaMessageStream_listeners = new WeakMap(), _BetaMessageStream_ended = new WeakMap(), _BetaMessageStream_errored = new WeakMap(), _BetaMessageStream_aborted = new WeakMap(), _BetaMessageStream_catchingPromiseCreated = new WeakMap(), _BetaMessageStream_response = new WeakMap(), _BetaMessageStream_request_id = new WeakMap(), _BetaMessageStream_logger = new WeakMap(), _BetaMessageStream_handleError = new WeakMap(), _BetaMessageStream_instances = new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage() { if (this.receivedMessages.length === 0) { throw new error_AnthropicError('stream ended without producing a Message with role=assistant'); } @@ -98723,7 +95349,7 @@ class BetaMessageStream { } case 'message_stop': { this._addMessageParam(messageSnapshot); - this._addMessage(maybeParseBetaMessage(messageSnapshot, __classPrivateFieldGet(this, _BetaMessageStream_params, "f")), true); + this._addMessage(maybeParseBetaMessage(messageSnapshot, __classPrivateFieldGet(this, _BetaMessageStream_params, "f"), { logger: __classPrivateFieldGet(this, _BetaMessageStream_logger, "f") }), true); break; } case 'content_block_stop': { @@ -98747,7 +95373,7 @@ class BetaMessageStream { throw new error_AnthropicError(`request ended without sending any chunks`); } __classPrivateFieldSet(this, _BetaMessageStream_currentMessageSnapshot, undefined, "f"); - return maybeParseBetaMessage(snapshot, __classPrivateFieldGet(this, _BetaMessageStream_params, "f")); + return maybeParseBetaMessage(snapshot, __classPrivateFieldGet(this, _BetaMessageStream_params, "f"), { logger: __classPrivateFieldGet(this, _BetaMessageStream_logger, "f") }); }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage(event) { let snapshot = __classPrivateFieldGet(this, _BetaMessageStream_currentMessageSnapshot, "f"); if (event.type === 'message_start') { @@ -99412,7 +96038,7 @@ class Batches extends APIResource { */ retrieve(messageBatchID, params = {}, options) { const { betas } = params ?? {}; - return this._client.get(path `/v1/messages/batches/${messageBatchID}?beta=true`, { + return this._client.get(path_path `/v1/messages/batches/${messageBatchID}?beta=true`, { ...options, headers: buildHeaders([ { 'anthropic-beta': [...(betas ?? []), 'message-batches-2024-09-24'].toString() }, @@ -99465,7 +96091,7 @@ class Batches extends APIResource { */ delete(messageBatchID, params = {}, options) { const { betas } = params ?? {}; - return this._client.delete(path `/v1/messages/batches/${messageBatchID}?beta=true`, { + return this._client.delete(path_path `/v1/messages/batches/${messageBatchID}?beta=true`, { ...options, headers: buildHeaders([ { 'anthropic-beta': [...(betas ?? []), 'message-batches-2024-09-24'].toString() }, @@ -99497,7 +96123,7 @@ class Batches extends APIResource { */ cancel(messageBatchID, params = {}, options) { const { betas } = params ?? {}; - return this._client.post(path `/v1/messages/batches/${messageBatchID}/cancel?beta=true`, { + return this._client.post(path_path `/v1/messages/batches/${messageBatchID}/cancel?beta=true`, { ...options, headers: buildHeaders([ { 'anthropic-beta': [...(betas ?? []), 'message-batches-2024-09-24'].toString() }, @@ -99597,7 +96223,7 @@ class Messages extends APIResource { } /** * Send a structured list of input messages with text and/or image content, along with an expected `output_format` and - * the response will be automatically parsed and available in the `parsed` property of the message. + * the response will be automatically parsed and available in the `parsed_output` property of the message. * * @example * ```ts @@ -99608,7 +96234,7 @@ class Messages extends APIResource { * output_format: zodOutputFormat(z.object({ answer: z.number() }), 'math'), * }); * - * console.log(message.parsed?.answer); // 4 + * console.log(message.parsed_output?.answer); // 4 * ``` */ parse(params, options) { @@ -99619,7 +96245,7 @@ class Messages extends APIResource { options?.headers, ]), }; - return this.create(params, options).then((message) => parseBetaMessage(message, params)); + return this.create(params, options).then((message) => parseBetaMessage(message, params, { logger: this._client.logger ?? console })); } /** * Create a Message stream @@ -99684,7 +96310,7 @@ class Versions extends APIResource { */ create(skillID, params = {}, options) { const { betas, ...body } = params ?? {}; - return this._client.post(path `/v1/skills/${skillID}/versions?beta=true`, multipartFormRequestOptions({ + return this._client.post(path_path `/v1/skills/${skillID}/versions?beta=true`, multipartFormRequestOptions({ body, ...options, headers: buildHeaders([ @@ -99706,7 +96332,7 @@ class Versions extends APIResource { */ retrieve(version, params, options) { const { skill_id, betas } = params; - return this._client.get(path `/v1/skills/${skill_id}/versions/${version}?beta=true`, { + return this._client.get(path_path `/v1/skills/${skill_id}/versions/${version}?beta=true`, { ...options, headers: buildHeaders([ { 'anthropic-beta': [...(betas ?? []), 'skills-2025-10-02'].toString() }, @@ -99729,7 +96355,7 @@ class Versions extends APIResource { */ list(skillID, params = {}, options) { const { betas, ...query } = params ?? {}; - return this._client.getAPIList(path `/v1/skills/${skillID}/versions?beta=true`, (PageCursor), { + return this._client.getAPIList(path_path `/v1/skills/${skillID}/versions?beta=true`, (PageCursor), { query, ...options, headers: buildHeaders([ @@ -99751,7 +96377,7 @@ class Versions extends APIResource { */ delete(version, params, options) { const { skill_id, betas } = params; - return this._client.delete(path `/v1/skills/${skill_id}/versions/${version}?beta=true`, { + return this._client.delete(path_path `/v1/skills/${skill_id}/versions/${version}?beta=true`, { ...options, headers: buildHeaders([ { 'anthropic-beta': [...(betas ?? []), 'skills-2025-10-02'].toString() }, @@ -99804,7 +96430,7 @@ class Skills extends APIResource { */ retrieve(skillID, params = {}, options) { const { betas } = params ?? {}; - return this._client.get(path `/v1/skills/${skillID}?beta=true`, { + return this._client.get(path_path `/v1/skills/${skillID}?beta=true`, { ...options, headers: buildHeaders([ { 'anthropic-beta': [...(betas ?? []), 'skills-2025-10-02'].toString() }, @@ -99844,7 +96470,7 @@ class Skills extends APIResource { */ delete(skillID, params = {}, options) { const { betas } = params ?? {}; - return this._client.delete(path `/v1/skills/${skillID}?beta=true`, { + return this._client.delete(path_path `/v1/skills/${skillID}?beta=true`, { ...options, headers: buildHeaders([ { 'anthropic-beta': [...(betas ?? []), 'skills-2025-10-02'].toString() }, @@ -99983,6 +96609,7 @@ class MessageStream { * as no `Response` is available. */ async withResponse() { + __classPrivateFieldSet(this, _MessageStream_catchingPromiseCreated, true, "f"); const response = await __classPrivateFieldGet(this, _MessageStream_connectedPromise, "f"); if (!response) { throw new Error('Could not resolve a `Response` object'); @@ -100540,7 +97167,7 @@ class batches_Batches extends APIResource { * ``` */ retrieve(messageBatchID, options) { - return this._client.get(path `/v1/messages/batches/${messageBatchID}`, options); + return this._client.get(path_path `/v1/messages/batches/${messageBatchID}`, options); } /** * List all Message Batches within a Workspace. Most recently created batches are @@ -100576,7 +97203,7 @@ class batches_Batches extends APIResource { * ``` */ delete(messageBatchID, options) { - return this._client.delete(path `/v1/messages/batches/${messageBatchID}`, options); + return this._client.delete(path_path `/v1/messages/batches/${messageBatchID}`, options); } /** * Batches may be canceled any time before processing ends. Once cancellation is @@ -100600,7 +97227,7 @@ class batches_Batches extends APIResource { * ``` */ cancel(messageBatchID, options) { - return this._client.post(path `/v1/messages/batches/${messageBatchID}/cancel`, options); + return this._client.post(path_path `/v1/messages/batches/${messageBatchID}/cancel`, options); } /** * Streams the results of a Message Batch as a `.jsonl` file. @@ -100720,7 +97347,7 @@ class models_Models extends APIResource { */ retrieve(modelID, params = {}, options) { const { betas } = params ?? {}; - return this._client.get(path `/v1/models/${modelID}`, { + return this._client.get(path_path `/v1/models/${modelID}`, { ...options, headers: buildHeaders([ { ...(betas?.toString() != null ? { 'anthropic-beta': betas?.toString() } : undefined) }, @@ -100776,7 +97403,7 @@ const readEnv = (env) => { //# sourceMappingURL=env.mjs.map ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/client.mjs // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -var _BaseAnthropic_instances, client_a, _BaseAnthropic_encoder, _BaseAnthropic_baseURLOverridden; +var _BaseAnthropic_instances, _a, _BaseAnthropic_encoder, _BaseAnthropic_baseURLOverridden; @@ -100833,7 +97460,7 @@ class BaseAnthropic { throw new error_AnthropicError("It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\n"); } this.baseURL = options.baseURL; - this.timeout = options.timeout ?? client_a.DEFAULT_TIMEOUT /* 10 minutes */; + this.timeout = options.timeout ?? _a.DEFAULT_TIMEOUT /* 10 minutes */; this.logger = options.logger ?? console; const defaultLogLevel = 'warn'; // Set default logLevel early so that we can log a warning in parseLogLevel. @@ -101282,10 +97909,10 @@ class BaseAnthropic { } } } -client_a = BaseAnthropic, _BaseAnthropic_encoder = new WeakMap(), _BaseAnthropic_instances = new WeakSet(), _BaseAnthropic_baseURLOverridden = function _BaseAnthropic_baseURLOverridden() { +_a = BaseAnthropic, _BaseAnthropic_encoder = new WeakMap(), _BaseAnthropic_instances = new WeakSet(), _BaseAnthropic_baseURLOverridden = function _BaseAnthropic_baseURLOverridden() { return this.baseURL !== 'https://api.anthropic.com'; }; -BaseAnthropic.Anthropic = client_a; +BaseAnthropic.Anthropic = _a; BaseAnthropic.HUMAN_PROMPT = HUMAN_PROMPT; BaseAnthropic.AI_PROMPT = AI_PROMPT; BaseAnthropic.DEFAULT_TIMEOUT = 600000; // 10 minutes @@ -101329,8 +97956,161 @@ Anthropic.Beta = Beta; //# sourceMappingURL=index.mjs.map -// EXTERNAL MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/lib/transform-json-schema.js -var transform_json_schema = __nccwpck_require__(1252); +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/internal/utils/base64.mjs +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + +const toBase64 = (data) => { + if (!data) + return ''; + if (typeof globalThis.Buffer !== 'undefined') { + return globalThis.Buffer.from(data).toString('base64'); + } + if (typeof data === 'string') { + data = encodeUTF8(data); + } + if (typeof btoa !== 'undefined') { + return btoa(String.fromCharCode.apply(null, data)); + } + throw new AnthropicError('Cannot generate base64 string; Expected `Buffer` or `btoa` to be defined'); +}; +const fromBase64 = (str) => { + if (typeof globalThis.Buffer !== 'undefined') { + const buf = globalThis.Buffer.from(str, 'base64'); + return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); + } + if (typeof atob !== 'undefined') { + const bstr = atob(str); + const buf = new Uint8Array(bstr.length); + for (let i = 0; i < bstr.length; i++) { + buf[i] = bstr.charCodeAt(i); + } + return buf; + } + throw new AnthropicError('Cannot decode base64 string; Expected `Buffer` or `atob` to be defined'); +}; +//# sourceMappingURL=base64.mjs.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/internal/utils.mjs +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + + + + + +//# sourceMappingURL=utils.mjs.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/lib/transform-json-schema.mjs + +// Supported string formats +const SUPPORTED_STRING_FORMATS = new Set([ + 'date-time', + 'time', + 'date', + 'duration', + 'email', + 'hostname', + 'uri', + 'ipv4', + 'ipv6', + 'uuid', +]); +function transform_json_schema_deepClone(obj) { + return JSON.parse(JSON.stringify(obj)); +} +function transformJSONSchema(jsonSchema) { + const workingCopy = transform_json_schema_deepClone(jsonSchema); + return _transformJSONSchema(workingCopy); +} +function _transformJSONSchema(jsonSchema) { + const strictSchema = {}; + const ref = pop(jsonSchema, '$ref'); + if (ref !== undefined) { + strictSchema['$ref'] = ref; + return strictSchema; + } + const defs = pop(jsonSchema, '$defs'); + if (defs !== undefined) { + const strictDefs = {}; + strictSchema['$defs'] = strictDefs; + for (const [name, defSchema] of Object.entries(defs)) { + strictDefs[name] = _transformJSONSchema(defSchema); + } + } + const type = pop(jsonSchema, 'type'); + const anyOf = pop(jsonSchema, 'anyOf'); + const oneOf = pop(jsonSchema, 'oneOf'); + const allOf = pop(jsonSchema, 'allOf'); + if (Array.isArray(anyOf)) { + strictSchema['anyOf'] = anyOf.map((variant) => _transformJSONSchema(variant)); + } + else if (Array.isArray(oneOf)) { + strictSchema['anyOf'] = oneOf.map((variant) => _transformJSONSchema(variant)); + } + else if (Array.isArray(allOf)) { + strictSchema['allOf'] = allOf.map((entry) => _transformJSONSchema(entry)); + } + else { + if (type === undefined) { + throw new Error('JSON schema must have a type defined if anyOf/oneOf/allOf are not used'); + } + strictSchema['type'] = type; + } + const description = pop(jsonSchema, 'description'); + if (description !== undefined) { + strictSchema['description'] = description; + } + const title = pop(jsonSchema, 'title'); + if (title !== undefined) { + strictSchema['title'] = title; + } + if (type === 'object') { + const properties = pop(jsonSchema, 'properties') || {}; + strictSchema['properties'] = Object.fromEntries(Object.entries(properties).map(([key, propSchema]) => [ + key, + _transformJSONSchema(propSchema), + ])); + pop(jsonSchema, 'additionalProperties'); + strictSchema['additionalProperties'] = false; + const required = pop(jsonSchema, 'required'); + if (required !== undefined) { + strictSchema['required'] = required; + } + } + else if (type === 'string') { + const format = pop(jsonSchema, 'format'); + if (format !== undefined && SUPPORTED_STRING_FORMATS.has(format)) { + strictSchema['format'] = format; + } + else if (format !== undefined) { + jsonSchema['format'] = format; + } + } + else if (type === 'array') { + const items = pop(jsonSchema, 'items'); + if (items !== undefined) { + strictSchema['items'] = _transformJSONSchema(items); + } + const minItems = pop(jsonSchema, 'minItems'); + if (minItems !== undefined && (minItems === 0 || minItems === 1)) { + strictSchema['minItems'] = minItems; + } + else if (minItems !== undefined) { + jsonSchema['minItems'] = minItems; + } + } + if (Object.keys(jsonSchema).length > 0) { + const existingDescription = strictSchema['description']; + strictSchema['description'] = + (existingDescription ? existingDescription + '\n\n' : '') + + '{' + + Object.entries(jsonSchema) + .map(([key, value]) => `${key}: ${JSON.stringify(value)}`) + .join(', ') + + '}'; + } + return strictSchema; +} +//# sourceMappingURL=transform-json-schema.mjs.map ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/chat_models.js @@ -101393,12 +98173,18 @@ function isBuiltinTool(tool) { "str_replace_editor_", "str_replace_based_edit_tool_", "code_execution_", - "memory_" + "memory_", + "tool_search_", + "mcp_toolset" ]; - return typeof tool === "object" && tool !== null && "type" in tool && "name" in tool && typeof tool.type === "string" && builtInToolPrefixes.some((prefix) => typeof tool.type === "string" && tool.type.startsWith(prefix)); + return typeof tool === "object" && tool !== null && "type" in tool && ("name" in tool || "mcp_server_name" in tool) && typeof tool.type === "string" && builtInToolPrefixes.some((prefix) => typeof tool.type === "string" && tool.type.startsWith(prefix)); } -function _combineBetas(a, b) { - return Array.from(new Set([...a ?? [], ...b ?? []])); +function _combineBetas(a, b, ...rest) { + return Array.from(new Set([ + ...a ?? [], + ...b ?? [], + ...rest.flatMap((x) => Array.from(x)) + ])); } function extractToken(chunk) { if (typeof chunk.content === "string") return chunk.content; @@ -101662,6 +98448,92 @@ function extractToken(chunk) { *
* *
+* Tool Search +* +* Tool search enables Claude to dynamically discover and load tools on-demand +* instead of loading all tool definitions upfront. This is useful when you have +* many tools but want to avoid the overhead of sending all definitions with every request. +* +* ```typescript +* import { ChatAnthropic } from "@langchain/anthropic"; +* +* const model = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* }); +* +* const tools = [ +* // Tool search server tool +* { +* type: "tool_search_tool_regex_20251119", +* name: "tool_search_tool_regex", +* }, +* // Tools with defer_loading are loaded on-demand +* { +* name: "get_weather", +* description: "Get the current weather for a location", +* input_schema: { +* type: "object", +* properties: { +* location: { type: "string", description: "City name" }, +* unit: { +* type: "string", +* enum: ["celsius", "fahrenheit"], +* }, +* }, +* required: ["location"], +* }, +* defer_loading: true, // Tool is loaded on-demand +* }, +* { +* name: "search_files", +* description: "Search through files in the workspace", +* input_schema: { +* type: "object", +* properties: { +* query: { type: "string" }, +* }, +* required: ["query"], +* }, +* defer_loading: true, // Tool is loaded on-demand +* }, +* ]; +* +* const modelWithTools = model.bindTools(tools); +* const response = await modelWithTools.invoke("What's the weather in San Francisco?"); +* ``` +* +* You can also use the `tool()` helper with the `extras` field: +* +* ```typescript +* import { tool } from "@langchain/core/tools"; +* import { z } from "zod"; +* +* const getWeather = tool( +* async (input) => `Weather in ${input.location}`, +* { +* name: "get_weather", +* description: "Get weather for a location", +* schema: z.object({ location: z.string() }), +* extras: { defer_loading: true }, +* } +* ); +* ``` +* +* **Note:** The required `advanced-tool-use-2025-11-20` beta header is automatically +* appended to the request when using tool search tools. +* +* **Best practices:** +* - Tools with `defer_loading: true` are only loaded when Claude discovers them via search +* - Keep your 3-5 most frequently used tools as non-deferred for optimal performance +* - Both regex and bm25 variants search tool names, descriptions, and argument info +* +* See the {@link https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool | Claude docs} +* for more information. +*
+* +*
+* +*
* Structured Output * * ChatAnthropic supports structured output through two main approaches: @@ -101917,8 +98789,9 @@ var ChatAnthropicMessages = class extends BaseChatModel { * @returns {AnthropicTool[] | undefined} The formatted tools, or undefined if none are passed. */ formatStructuredToolToAnthropic(tools) { - if (!tools || !tools.length) return void 0; + if (!tools) return void 0; return tools.map((tool) => { + if (isLangChainTool(tool) && tool.extras?.providerToolDefinition) return tool.extras.providerToolDefinition; if (isBuiltinTool(tool)) return tool; if (isAnthropicTool(tool)) return tool; if (isOpenAITool(tool)) return { @@ -101929,7 +98802,8 @@ var ChatAnthropicMessages = class extends BaseChatModel { if (isLangChainTool(tool)) return { name: tool.name, description: tool.description, - input_schema: isInteropZodSchema(tool.schema) ? toJsonSchema(tool.schema) : tool.schema + input_schema: isInteropZodSchema(tool.schema) ? toJsonSchema(tool.schema) : tool.schema, + ...tool.extras ? AnthropicToolExtrasSchema.parse(tool.extras) : {} }; throw new Error(`Unknown tool type passed to ChatAnthropic: ${JSON.stringify(tool, null, 2)}`); }); @@ -101945,29 +98819,15 @@ var ChatAnthropicMessages = class extends BaseChatModel { */ invocationParams(options) { const tool_choice = handleToolChoice(options?.tool_choice); - if (this.thinking.type === "enabled") { - if (this.topP !== void 0 && this.topK !== -1) throw new Error("topK is not supported when thinking is enabled"); - if (this.temperature !== void 0 && this.temperature !== 1) throw new Error("temperature is not supported when thinking is enabled"); - return { - model: this.model, - stop_sequences: options?.stop ?? this.stopSequences, - stream: this.streaming, - max_tokens: this.maxTokens, - tools: this.formatStructuredToolToAnthropic(options?.tools), - tool_choice, - thinking: this.thinking, - context_management: this.contextManagement, - ...this.invocationKwargs, - container: options?.container, - betas: _combineBetas(this.betas, options?.betas), - output_format: options?.output_format - }; - } - return { + const toolBetas = options?.tools?.reduce((acc, tool) => { + if (typeof tool === "object" && "type" in tool && tool.type in ANTHROPIC_TOOL_BETAS) { + const beta = ANTHROPIC_TOOL_BETAS[tool.type]; + if (!acc.includes(beta)) return [...acc, beta]; + } + return acc; + }, []); + const output = { model: this.model, - temperature: this.temperature, - top_k: this.topK, - top_p: this.topP, stop_sequences: options?.stop ?? this.stopSequences, stream: this.streaming, max_tokens: this.maxTokens, @@ -101977,9 +98837,19 @@ var ChatAnthropicMessages = class extends BaseChatModel { context_management: this.contextManagement, ...this.invocationKwargs, container: options?.container, - betas: _combineBetas(this.betas, options?.betas), - output_format: options?.output_format + betas: _combineBetas(this.betas, options?.betas, toolBetas ?? []), + output_format: options?.output_format, + mcp_servers: options?.mcp_servers }; + if (this.thinking.type === "enabled") { + if (this.topP !== void 0 && this.topK !== -1) throw new Error("topK is not supported when thinking is enabled"); + if (this.temperature !== void 0 && this.temperature !== 1) throw new Error("temperature is not supported when thinking is enabled"); + } else { + output.temperature = this.temperature; + output.top_k = this.topK; + output.top_p = this.topP; + } + return output; } /** @ignore */ _identifyingParams() { @@ -102181,7 +99051,7 @@ var ChatAnthropicMessages = class extends BaseChatModel { } if (method === "jsonSchema") { outputParser = isInteropZodSchema(schema) ? StructuredOutputParser.fromZodSchema(schema) : new JsonOutputParser(); - const jsonSchema = (0,transform_json_schema/* transformJSONSchema */.W)(toJsonSchema(schema)); + const jsonSchema = transformJSONSchema(toJsonSchema(schema)); llm = this.withConfig({ outputVersion: "v0", output_format: { @@ -102316,11 +99186,1048 @@ function convertPromptToAnthropic(formattedPrompt) { //#endregion //# sourceMappingURL=prompts.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/types.js + + +//#region src/tools/types.ts +/** +* Memory tool command types as defined by Anthropic's memory tool API. +* @beta +* @see https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/memory-tool +*/ +const Memory20250818ViewCommandSchema = object({ + command: literal("view"), + path: schemas_string() +}); +const Memory20250818CreateCommandSchema = object({ + command: literal("create"), + path: schemas_string(), + file_text: schemas_string() +}); +const Memory20250818StrReplaceCommandSchema = object({ + command: literal("str_replace"), + path: schemas_string(), + old_str: schemas_string(), + new_str: schemas_string() +}); +const Memory20250818InsertCommandSchema = object({ + command: literal("insert"), + path: schemas_string(), + insert_line: schemas_number(), + insert_text: schemas_string() +}); +const Memory20250818DeleteCommandSchema = object({ + command: literal("delete"), + path: schemas_string() +}); +const Memory20250818RenameCommandSchema = object({ + command: literal("rename"), + old_path: schemas_string(), + new_path: schemas_string() +}); +const Memory20250818CommandSchema = discriminatedUnion("command", [ + Memory20250818ViewCommandSchema, + Memory20250818CreateCommandSchema, + Memory20250818StrReplaceCommandSchema, + Memory20250818InsertCommandSchema, + Memory20250818DeleteCommandSchema, + Memory20250818RenameCommandSchema +]); +/** +* Text editor tool command types for Claude 4.x models. +* @see https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/text-editor-tool +*/ +const TextEditor20250728ViewCommandSchema = object({ + command: literal("view"), + path: schemas_string(), + view_range: tuple([schemas_number(), schemas_number()]).optional() +}); +const TextEditor20250728StrReplaceCommandSchema = object({ + command: literal("str_replace"), + path: schemas_string(), + old_str: schemas_string(), + new_str: schemas_string() +}); +const TextEditor20250728CreateCommandSchema = object({ + command: literal("create"), + path: schemas_string(), + file_text: schemas_string() +}); +const TextEditor20250728InsertCommandSchema = object({ + command: literal("insert"), + path: schemas_string(), + insert_line: schemas_number(), + new_str: schemas_string() +}); +const TextEditor20250728CommandSchema = discriminatedUnion("command", [ + TextEditor20250728ViewCommandSchema, + TextEditor20250728StrReplaceCommandSchema, + TextEditor20250728CreateCommandSchema, + TextEditor20250728InsertCommandSchema +]); +const coordinateSchema = tuple([schemas_number(), schemas_number()]); +const ComputerScreenshotActionSchema = object({ action: literal("screenshot") }); +const ComputerLeftClickActionSchema = object({ + action: literal("left_click"), + coordinate: coordinateSchema +}); +const ComputerRightClickActionSchema = object({ + action: literal("right_click"), + coordinate: coordinateSchema +}); +const ComputerMiddleClickActionSchema = object({ + action: literal("middle_click"), + coordinate: coordinateSchema +}); +const ComputerDoubleClickActionSchema = object({ + action: literal("double_click"), + coordinate: coordinateSchema +}); +const ComputerTripleClickActionSchema = object({ + action: literal("triple_click"), + coordinate: coordinateSchema +}); +const ComputerLeftClickDragActionSchema = object({ + action: literal("left_click_drag"), + start_coordinate: coordinateSchema, + end_coordinate: coordinateSchema +}); +const ComputerLeftMouseDownActionSchema = object({ + action: literal("left_mouse_down"), + coordinate: coordinateSchema +}); +const ComputerLeftMouseUpActionSchema = object({ + action: literal("left_mouse_up"), + coordinate: coordinateSchema +}); +const ComputerScrollActionSchema = object({ + action: literal("scroll"), + coordinate: coordinateSchema, + scroll_direction: schemas_enum([ + "up", + "down", + "left", + "right" + ]), + scroll_amount: schemas_number() +}); +const ComputerTypeActionSchema = object({ + action: literal("type"), + text: schemas_string() +}); +const ComputerKeyActionSchema = object({ + action: literal("key"), + key: schemas_string() +}); +const ComputerMouseMoveActionSchema = object({ + action: literal("mouse_move"), + coordinate: coordinateSchema +}); +const ComputerHoldKeyActionSchema = object({ + action: literal("hold_key"), + key: schemas_string() +}); +const ComputerWaitActionSchema = object({ + action: literal("wait"), + duration: schemas_number().optional() +}); +const ComputerZoomActionSchema = object({ + action: literal("zoom"), + region: tuple([ + schemas_number(), + schemas_number(), + schemas_number(), + schemas_number() + ]) +}); +const Computer20250124ActionSchema = discriminatedUnion("action", [ + ComputerScreenshotActionSchema, + ComputerLeftClickActionSchema, + ComputerRightClickActionSchema, + ComputerMiddleClickActionSchema, + ComputerDoubleClickActionSchema, + ComputerTripleClickActionSchema, + ComputerLeftClickDragActionSchema, + ComputerLeftMouseDownActionSchema, + ComputerLeftMouseUpActionSchema, + ComputerScrollActionSchema, + ComputerTypeActionSchema, + ComputerKeyActionSchema, + ComputerMouseMoveActionSchema, + ComputerHoldKeyActionSchema, + ComputerWaitActionSchema +]); +const Computer20251124ActionSchema = discriminatedUnion("action", [ + ComputerScreenshotActionSchema, + ComputerLeftClickActionSchema, + ComputerRightClickActionSchema, + ComputerMiddleClickActionSchema, + ComputerDoubleClickActionSchema, + ComputerTripleClickActionSchema, + ComputerLeftClickDragActionSchema, + ComputerLeftMouseDownActionSchema, + ComputerLeftMouseUpActionSchema, + ComputerScrollActionSchema, + ComputerTypeActionSchema, + ComputerKeyActionSchema, + ComputerMouseMoveActionSchema, + ComputerHoldKeyActionSchema, + ComputerWaitActionSchema, + ComputerZoomActionSchema +]); +/** +* Bash tool command types for Claude 4 models and Claude 3.7. +* @see https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/bash-tool +*/ +const Bash20250124ExecuteCommandSchema = object({ command: schemas_string().describe("The bash command to run") }); +const Bash20250124RestartCommandSchema = object({ restart: literal(true).describe("Set to true to restart the bash session") }); +const Bash20250124CommandSchema = union([Bash20250124ExecuteCommandSchema, Bash20250124RestartCommandSchema]); + +//#endregion + +//# sourceMappingURL=types.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/memory.js + + + +//#region src/tools/memory.ts +/** +* Creates an Anthropic memory tool that can be used with ChatAnthropic. +* +* The memory tool enables Claude to store and retrieve information across conversations +* through a memory file directory. Claude can create, read, update, and delete files that +* persist between sessions, allowing it to build knowledge over time without keeping +* everything in the context window. +* +* @example +* ```typescript +* import { ChatAnthropic, memory_20250818 } from "@langchain/anthropic"; +* +* const llm = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929" +* }); +* +* const memory = memory_20250818({ +* execute: async (args) => { +* // handle memory command execution +* // ... +* }, +* }); +* const llmWithMemory = llm.bindTools([memory]); +* +* const response = await llmWithMemory.invoke("Remember that I like Python"); +* ``` +* +* @param options - Optional configuration for the memory tool (currently unused) +* @param options.execute - Optional execute function that handles memory command execution. +* @returns The memory tool object that can be passed to `bindTools` +* +* @see https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/memory-tool +*/ +function memory_20250818(options) { + const memoryTool = tool(options?.execute, { + name: "memory", + schema: Memory20250818CommandSchema + }); + memoryTool.extras = { + ...memoryTool.extras ?? {}, + providerToolDefinition: { + type: "memory_20250818", + name: "memory" + } + }; + return memoryTool; +} + +//#endregion + +//# sourceMappingURL=memory.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/webSearch.js +//#region src/tools/webSearch.ts +/** +* Creates a web search tool that gives Claude direct access to real-time web content, +* allowing it to answer questions with up-to-date information beyond its knowledge cutoff. +* Claude automatically cites sources from search results as part of its answer. +* +* @see {@link https://docs.anthropic.com/en/docs/build-with-claude/tool-use/web-search-tool | Anthropic Web Search Documentation} +* @param options - Configuration options for the web search tool +* @returns A web search tool definition to be passed to the Anthropic API +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* +* const model = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* }); +* +* // Basic usage +* const response = await model.invoke("What is the weather in NYC?", { +* tools: [tools.webSearch_20250305()], +* }); +* +* // With options +* const responseWithOptions = await model.invoke("Latest news about AI?", { +* tools: [tools.webSearch_20250305({ +* maxUses: 5, +* allowedDomains: ["reuters.com", "bbc.com"], +* userLocation: { +* type: "approximate", +* city: "San Francisco", +* region: "California", +* country: "US", +* timezone: "America/Los_Angeles", +* }, +* })], +* }); +* ``` +*/ +function webSearch_20250305(options) { + return { + type: "web_search_20250305", + name: "web_search", + max_uses: options?.maxUses, + allowed_domains: options?.allowedDomains, + blocked_domains: options?.blockedDomains, + cache_control: options?.cacheControl, + defer_loading: options?.deferLoading, + strict: options?.strict, + user_location: options?.userLocation + }; +} + +//#endregion + +//# sourceMappingURL=webSearch.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/webFetch.js +//#region src/tools/webFetch.ts +/** +* Creates a web fetch tool that allows Claude to retrieve full content from specified +* web pages and PDF documents. Claude can only fetch URLs that have been explicitly +* provided by the user or that come from previous web search or web fetch results. +* +* @warning Enabling the web fetch tool in environments where Claude processes untrusted +* input alongside sensitive data poses data exfiltration risks. We recommend only using +* this tool in trusted environments or when handling non-sensitive data. +* +* @see {@link https://docs.anthropic.com/en/docs/build-with-claude/tool-use/web-fetch-tool | Anthropic Web Fetch Documentation} +* @param options - Configuration options for the web fetch tool +* @returns A web fetch tool definition to be passed to the Anthropic API +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* +* const model = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* }); +* +* // Basic usage - fetch content from a URL +* const response = await model.invoke( +* "Please analyze the content at https://example.com/article", +* { tools: [tools.webFetch_20250910()] } +* ); +* +* // With options +* const responseWithOptions = await model.invoke( +* "Summarize this research paper: https://arxiv.org/abs/2024.12345", +* { +* tools: [tools.webFetch_20250910({ +* maxUses: 5, +* allowedDomains: ["arxiv.org", "example.com"], +* citations: { enabled: true }, +* maxContentTokens: 50000, +* })], +* } +* ); +* +* // Combined with web search for comprehensive information gathering +* const combinedResponse = await model.invoke( +* "Find recent articles about quantum computing and analyze the most relevant one", +* { +* tools: [ +* tools.webSearch_20250305({ maxUses: 3 }), +* tools.webFetch_20250910({ maxUses: 5, citations: { enabled: true } }), +* ], +* } +* ); +* ``` +*/ +function webFetch_20250910(options) { + return { + type: "web_fetch_20250910", + name: "web_fetch", + max_uses: options?.maxUses, + allowed_domains: options?.allowedDomains, + blocked_domains: options?.blockedDomains, + cache_control: options?.cacheControl, + citations: options?.citations, + max_content_tokens: options?.maxContentTokens + }; +} + +//#endregion + +//# sourceMappingURL=webFetch.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/toolSearch.js +//#region src/tools/toolSearch.ts +/** +* Creates a regex-based tool search tool that enables Claude to work with hundreds +* or thousands of tools by dynamically discovering and loading them on-demand. +* Claude constructs regex patterns (using Python's `re.search()` syntax) to search +* for tools by name, description, argument names, and argument descriptions. +* +* @note This tool requires the beta header `advanced-tool-use-2025-11-20` in API requests. +* +* @see {@link https://docs.anthropic.com/en/docs/build-with-claude/tool-use/tool-search-tool | Anthropic Tool Search Documentation} +* @param options - Configuration options for the tool search tool +* @returns A tool search tool definition to be passed to the Anthropic API +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* +* const model = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* }); +* +* const getWeather = tool( +* async (input: { location: string }) => { +* return `Weather in ${input.location}`; +* }, +* { +* name: "get_weather", +* description: "Get the weather at a specific location", +* schema: z.object({ +* location: z.string(), +* }), +* extras: { defer_loading: true }, +* }, +* ); +* +* // Use with deferred tools - Claude will search and discover tools as needed +* const response = await model.invoke("What is the weather in San Francisco?", { +* tools: [ +* tools.toolSearchRegex_20251119(), +* getWeather, +* ], +* }); +* ``` +*/ +function toolSearchRegex_20251119(options) { + return { + type: "tool_search_tool_regex_20251119", + name: "tool_search_tool_regex", + cache_control: options?.cacheControl + }; +} +/** +* Creates a BM25-based tool search tool that enables Claude to work with hundreds +* or thousands of tools by dynamically discovering and loading them on-demand. +* Claude uses natural language queries to search for tools by name, description, +* argument names, and argument descriptions. +* +* @note This tool requires the beta header `advanced-tool-use-2025-11-20` in API requests. +* +* @see {@link https://docs.anthropic.com/en/docs/build-with-claude/tool-use/tool-search-tool | Anthropic Tool Search Documentation} +* @param options - Configuration options for the tool search tool +* @returns A tool search tool definition to be passed to the Anthropic API +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* +* const model = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* clientOptions: { +* defaultHeaders: { "anthropic-beta": "advanced-tool-use-2025-11-20" }, +* }, +* }); +* +* const getWeather = tool( +* async (input: { location: string }) => { +* return `Weather in ${input.location}`; +* }, +* { +* name: "get_weather", +* description: "Get the weather at a specific location", +* schema: z.object({ +* location: z.string(), +* }), +* extras: { defer_loading: true }, +* }, +* ); +* +* // Use with deferred tools - Claude will search using natural language +* const response = await model.invoke("What is the weather in San Francisco?", { +* tools: [ +* tools.toolSearchBM25_20251119(), +* getWeather, +* ], +* }); +* ``` +*/ +function toolSearchBM25_20251119(options) { + return { + type: "tool_search_tool_bm25_20251119", + name: "tool_search_tool_bm25", + cache_control: options?.cacheControl + }; +} + +//#endregion + +//# sourceMappingURL=toolSearch.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/textEditor.js + + + +//#region src/tools/textEditor.ts +/** +* Creates an Anthropic text editor tool for Claude 4.x models that can view and modify text files. +* +* The text editor tool enables Claude to view and modify text files, helping debug, fix, +* and improve code or other text documents. Claude can directly interact with files, +* providing hands-on assistance rather than just suggesting changes. +* +* Available commands: +* - `view`: Examine file contents or list directory contents +* - `str_replace`: Replace specific text in a file +* - `create`: Create a new file with specified content +* - `insert`: Insert text at a specific line number +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* import * as fs from "fs"; +* +* const llm = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* }); +* +* const textEditor = tools.textEditor_20250728({ +* execute: async (args) => { +* if (args.command === "view") { +* const content = fs.readFileSync(args.path, "utf-8"); +* return content.split("\n").map((line, i) => `${i + 1}: ${line}`).join("\n"); +* } +* if (args.command === "str_replace") { +* let content = fs.readFileSync(args.path, "utf-8"); +* content = content.replace(args.old_str!, args.new_str!); +* fs.writeFileSync(args.path, content); +* return "Successfully replaced text."; +* } +* // Handle other commands... +* return "Command executed"; +* }, +* maxCharacters: 10000, +* }); +* +* const llmWithEditor = llm.bindTools([textEditor]); +* const response = await llmWithEditor.invoke( +* "There's a syntax error in my primes.py file. Can you help me fix it?" +* ); +* ``` +* +* @param options - Configuration options for the text editor tool +* @param options.execute - Function that handles text editor command execution +* @param options.maxCharacters - Maximum characters to return when viewing files +* @returns The text editor tool object that can be passed to `bindTools` +* +* @see https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/text-editor-tool +*/ +function textEditor_20250728(options) { + const name = "str_replace_based_edit_tool"; + const textEditorTool = tool(options?.execute, { + name, + description: "A tool for editing text files", + schema: TextEditor20250728CommandSchema + }); + textEditorTool.extras = { + ...textEditorTool.extras ?? {}, + providerToolDefinition: { + type: "text_editor_20250728", + name, + ...options?.maxCharacters !== void 0 && { max_characters: options.maxCharacters } + } + }; + return textEditorTool; +} + +//#endregion + +//# sourceMappingURL=textEditor.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/computer.js + + + +//#region src/tools/computer.ts +const TOOL_NAME = "computer"; +/** +* Creates an Anthropic computer use tool for Claude Opus 4.5 that provides +* screenshot capabilities and mouse/keyboard control for autonomous desktop interaction. +* +* The computer use tool enables Claude to interact with desktop environments through: +* - **Screenshot capture**: See what's currently displayed on screen +* - **Mouse control**: Click, drag, and move the cursor +* - **Keyboard input**: Type text and use keyboard shortcuts +* - **Zoom**: View specific screen regions at full resolution (when enabled) +* +* @warning Computer use is a beta feature with unique risks. Use a dedicated virtual machine +* or container with minimal privileges. Avoid giving access to sensitive data. +* +* @see {@link https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool | Anthropic Computer Use Documentation} +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* +* const llm = new ChatAnthropic({ +* model: "claude-opus-4-5-20251101", +* clientOptions: { +* defaultHeaders: { +* "anthropic-beta": "computer-use-2025-11-24", +* }, +* }, +* }); +* +* const computer = tools.computer_20251124({ +* displayWidthPx: 1024, +* displayHeightPx: 768, +* displayNumber: 1, +* enableZoom: true, +* execute: async (action) => { +* if (action.action === "screenshot") { +* // Capture and return base64-encoded screenshot +* return captureScreenshot(); +* } +* if (action.action === "left_click") { +* // Click at the specified coordinates +* await click(action.coordinate[0], action.coordinate[1]); +* return captureScreenshot(); +* } +* // Handle other actions... +* }, +* }); +* +* const llmWithComputer = llm.bindTools([computer]); +* const response = await llmWithComputer.invoke( +* "Save a picture of a cat to my desktop." +* ); +* ``` +* +* @param options - Configuration options for the computer use tool +* @returns The computer use tool object that can be passed to `bindTools` +*/ +function computer_20251124(options) { + const name = TOOL_NAME; + const computerTool = tool(options.execute, { + name, + schema: Computer20251124ActionSchema + }); + computerTool.extras = { + ...computerTool.extras ?? {}, + providerToolDefinition: { + type: "computer_20251124", + name, + display_width_px: options.displayWidthPx, + display_height_px: options.displayHeightPx, + ...options.displayNumber !== void 0 && { display_number: options.displayNumber }, + ...options.enableZoom !== void 0 && { enable_zoom: options.enableZoom } + } + }; + return computerTool; +} +/** +* Creates an Anthropic computer use tool that provides screenshot capabilities and mouse/keyboard control +* for autonomous desktop interaction. +* +* Supported models: Claude Sonnet 4.5, Haiku 4.5, Opus 4.1, Sonnet 4, Opus 4, and Sonnet 3.7 versions. +* +* The computer use tool enables Claude to interact with desktop environments through: +* - **Screenshot capture**: See what's currently displayed on screen +* - **Mouse control**: Click, drag, and move the cursor +* - **Keyboard input**: Type text and use keyboard shortcuts +* +* @warning Computer use is a beta feature with unique risks. Use a dedicated virtual machine +* or container with minimal privileges. Avoid giving access to sensitive data. +* +* @see {@link https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool | Anthropic Computer Use Documentation} +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* +* const llm = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* clientOptions: { +* defaultHeaders: { +* "anthropic-beta": "computer-use-2025-01-24", +* }, +* }, +* }); +* +* const computer = tools.computer_20250124({ +* displayWidthPx: 1024, +* displayHeightPx: 768, +* displayNumber: 1, +* execute: async (action) => { +* if (action.action === "screenshot") { +* // Capture and return base64-encoded screenshot +* return captureScreenshot(); +* } +* if (action.action === "left_click") { +* // Click at the specified coordinates +* await click(action.coordinate[0], action.coordinate[1]); +* return captureScreenshot(); +* } +* // Handle other actions... +* }, +* }); +* +* const llmWithComputer = llm.bindTools([computer]); +* const response = await llmWithComputer.invoke( +* "Save a picture of a cat to my desktop." +* ); +* ``` +* +* @param options - Configuration options for the computer use tool +* @returns The computer use tool object that can be passed to `bindTools` +*/ +function computer_20250124(options) { + const name = TOOL_NAME; + const computerTool = tool(options.execute, { + name, + description: "A tool for interacting with the computer", + schema: Computer20250124ActionSchema + }); + computerTool.extras = { + ...computerTool.extras ?? {}, + providerToolDefinition: { + type: "computer_20250124", + name, + display_width_px: options.displayWidthPx, + display_height_px: options.displayHeightPx, + ...options.displayNumber !== void 0 && { display_number: options.displayNumber } + } + }; + return computerTool; +} + +//#endregion + +//# sourceMappingURL=computer.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/codeExecution.js +//#region src/tools/codeExecution.ts +/** +* Creates a code execution tool that allows Claude to run Bash commands and manipulate files +* in a secure, sandboxed environment. Claude can analyze data, create visualizations, +* perform calculations, and process files. +* +* When this tool is provided, Claude automatically gains access to: +* - **Bash commands**: Execute shell commands for system operations +* - **File operations**: Create, view, and edit files directly +* +* @note This tool requires the beta header `code-execution-2025-08-25` in API requests. +* +* @see {@link https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/code-execution-tool | Anthropic Code Execution Documentation} +* @param options - Configuration options for the code execution tool +* @returns A code execution tool definition to be passed to the Anthropic API +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* +* const model = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* }); +* +* // Basic usage - calculations and data analysis +* const response = await model.invoke( +* "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", +* { tools: [tools.codeExecution_20250825()] } +* ); +* +* // File operations and visualization +* const response2 = await model.invoke( +* "Create a matplotlib visualization of sales data and save it as chart.png", +* { tools: [tools.codeExecution_20250825()] } +* ); +* ``` +* +* @example Container reuse +* ```typescript +* // First request - creates a container +* const response1 = await model.invoke( +* "Write a random number to /tmp/number.txt", +* { tools: [tools.codeExecution_20250825()] } +* ); +* +* // Extract container ID from response for reuse +* const containerId = response1.response_metadata?.container?.id; +* +* // Second request - reuse container to access the file +* const response2 = await model.invoke( +* "Read /tmp/number.txt and calculate its square", +* { +* tools: [tools.codeExecution_20250825()], +* // Pass container ID to reuse the same environment +* } +* ); +* ``` +*/ +function codeExecution_20250825(options) { + return { + type: "code_execution_20250825", + name: "code_execution", + cache_control: options?.cacheControl + }; +} + +//#endregion + +//# sourceMappingURL=codeExecution.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/bash.js + + + +//#region src/tools/bash.ts +/** +* Creates an Anthropic bash tool for Claude 4 models and Claude 3.7 that enables +* shell command execution in a persistent bash session. +* +* The bash tool provides Claude with: +* - **Persistent bash session**: Maintains state between commands +* - **Shell command execution**: Run any shell command +* - **Environment access**: Access to environment variables and working directory +* - **Command chaining**: Support for pipes, redirects, and scripting +* +* Available commands: +* - Execute a command: `{ command: "ls -la" }` +* - Restart the session: `{ restart: true }` +* +* @warning The bash tool provides direct system access. Implement safety measures +* such as running in isolated environments (Docker/VM), command filtering, +* and resource limits. +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* import { execSync } from "child_process"; +* +* const llm = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* }); +* +* const bash = tools.bash_20250124({ +* execute: async (args) => { +* if (args.restart) { +* // Reset session state +* return "Bash session restarted"; +* } +* try { +* const output = execSync(args.command!, { +* encoding: "utf-8", +* timeout: 30000, +* }); +* return output; +* } catch (error) { +* return `Error: ${error.message}`; +* } +* }, +* }); +* +* const llmWithBash = llm.bindTools([bash]); +* const response = await llmWithBash.invoke( +* "List all Python files in the current directory" +* ); +* +* // Outputs: "bash" +* console.log(response.tool_calls[0].name); +* // Outputs: "ls -la *.py 2>/dev/null || echo \"No Python files found in the current directory\" +* console.log(response.tool_calls[0].args.command); +* ``` +* +* @example Multi-step automation +* ```typescript +* // Claude can chain commands in a persistent session: +* // 1. cd /tmp +* // 2. echo "Hello" > test.txt +* // 3. cat test.txt // Works because we're still in /tmp +* ``` +* +* @param options - Configuration options for the bash tool +* @param options.execute - Function that handles bash command execution +* @returns The bash tool object that can be passed to `bindTools` +* +* @see https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/bash-tool +*/ +function bash_20250124(options) { + const name = "bash"; + const bashTool = tool(options?.execute, { + name, + description: "A tool for executing bash commands", + schema: Bash20250124CommandSchema + }); + bashTool.extras = { + ...bashTool.extras ?? {}, + providerToolDefinition: { + type: "bash_20250124", + name + } + }; + return bashTool; +} + +//#endregion + +//# sourceMappingURL=bash.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/mcpToolset.js +//#region src/tools/mcpToolset.ts +/** +* Creates an MCP toolset that connects to a remote MCP server to access its tools. +* This enables Claude to use tools from MCP servers without implementing a separate MCP client. +* +* @note This tool requires the beta header `mcp-client-2025-11-20` in API requests. +* The header is automatically added when using this tool. +* +* @see {@link https://docs.anthropic.com/en/docs/agents-and-tools/mcp-connector | Anthropic MCP Connector Documentation} +* @param options - Configuration options for the MCP toolset +* @returns An MCP toolset definition to be passed to the Anthropic API tools array +* +* @example +* ```typescript +* import { ChatAnthropic, tools } from "@langchain/anthropic"; +* +* const model = new ChatAnthropic({ +* model: "claude-sonnet-4-5-20250929", +* }); +* +* // Basic usage - enable all tools from an MCP server +* const response = await model.invoke("What tools do you have available?", { +* mcp_servers: [{ +* type: "url", +* url: "https://example-server.modelcontextprotocol.io/sse", +* name: "example-mcp", +* authorization_token: "YOUR_TOKEN", +* }], +* tools: [ +* tools.mcpToolset_20251120({ serverName: "example-mcp" }), +* ], +* }); +* +* // Allowlist pattern - enable only specific tools +* const responseAllowlist = await model.invoke("Search for events", { +* mcp_servers: [{ +* type: "url", +* url: "https://calendar.example.com/sse", +* name: "google-calendar-mcp", +* authorization_token: "YOUR_TOKEN", +* }], +* tools: [ +* tools.mcpToolset_20251120({ +* serverName: "google-calendar-mcp", +* defaultConfig: { enabled: false }, +* configs: { +* search_events: { enabled: true }, +* create_event: { enabled: true }, +* }, +* }), +* ], +* }); +* +* // Denylist pattern - disable specific tools +* const responseDenylist = await model.invoke("List my events", { +* mcp_servers: [{ +* type: "url", +* url: "https://calendar.example.com/sse", +* name: "google-calendar-mcp", +* authorization_token: "YOUR_TOKEN", +* }], +* tools: [ +* tools.mcpToolset_20251120({ +* serverName: "google-calendar-mcp", +* configs: { +* delete_all_events: { enabled: false }, +* share_calendar_publicly: { enabled: false }, +* }, +* }), +* ], +* }); +* +* // With deferred loading for use with Tool Search Tool +* const responseDeferred = await model.invoke("Search for tools", { +* mcp_servers: [{ +* type: "url", +* url: "https://example.com/sse", +* name: "example-mcp", +* }], +* tools: [ +* tools.toolSearchRegex_20251119(), +* tools.mcpToolset_20251120({ +* serverName: "example-mcp", +* defaultConfig: { deferLoading: true }, +* }), +* ], +* }); +* ``` +*/ +function mcpToolset_20251120(options) { + const defaultConfig = options.defaultConfig?.enabled !== void 0 || options.defaultConfig?.deferLoading !== void 0 ? { + enabled: options.defaultConfig?.enabled, + defer_loading: options.defaultConfig?.deferLoading + } : void 0; + const configs = options.configs ? Object.fromEntries(Object.entries(options.configs).map(([toolName, config]) => [toolName, { + enabled: config.enabled, + defer_loading: config.deferLoading + }])) : void 0; + return { + type: "mcp_toolset", + mcp_server_name: options.serverName, + default_config: defaultConfig, + configs, + cache_control: options.cacheControl + }; +} + +//#endregion + +//# sourceMappingURL=mcpToolset.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/tools/index.js + + + + + + + + + + +//#region src/tools/index.ts +const tools = { + memory_20250818: memory_20250818, + webSearch_20250305: webSearch_20250305, + webFetch_20250910: webFetch_20250910, + toolSearchRegex_20251119: toolSearchRegex_20251119, + toolSearchBM25_20251119: toolSearchBM25_20251119, + textEditor_20250728: textEditor_20250728, + computer_20251124: computer_20251124, + computer_20250124: computer_20250124, + codeExecution_20250825: codeExecution_20250825, + bash_20250124: bash_20250124, + mcpToolset_20251120: mcpToolset_20251120 +}; + +//#endregion + +//# sourceMappingURL=index.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/anthropic/dist/index.js + ;// CONCATENATED MODULE: ./src/providers/anthropic.provider.ts /** @@ -102346,7 +100253,8 @@ class AnthropicProvider { apiKey: this.apiKey, modelName: config.model || this.getDefaultModel(), temperature: config.temperature ?? 0.2, - maxTokens: config.maxTokens ?? 4000, + maxTokens: config.maxTokens ?? 50000, + streaming: true, }); } } @@ -102652,7 +100560,7 @@ const values_safeJSON = (text) => { const sleep_sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); //# sourceMappingURL=sleep.mjs.map ;// CONCATENATED MODULE: ./node_modules/openai/version.mjs -const version_VERSION = '6.9.1'; // x-release-please-version +const version_VERSION = '6.16.0'; // x-release-please-version //# sourceMappingURL=version.mjs.map ;// CONCATENATED MODULE: ./node_modules/openai/internal/detect-platform.mjs // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. @@ -103018,7 +100926,7 @@ function assign_single_source(target, source) { return acc; }, target); } -function utils_decode(str, _, charset) { +function decode(str, _, charset) { const strWithoutPlus = str.replace(/\+/g, ' '); if (charset === 'iso-8859-1') { // unescape never throws, no try...catch needed: @@ -103033,7 +100941,7 @@ function utils_decode(str, _, charset) { } } const limit = 1024; -const utils_encode = (str, _defaultEncoder, charset, _kind, format) => { +const encode = (str, _defaultEncoder, charset, _kind, format) => { // This code was originally written by Brian White for the io.js core querystring library. // It has been adapted here for stricter adherence to RFC 3986 if (str.length === 0) { @@ -103167,7 +101075,7 @@ const defaults = { delimiter: '&', encode: true, encodeDotInKeys: false, - encoder: utils_encode, + encoder: encode, encodeValuesOnly: false, format: default_format, formatter: default_formatter, @@ -104507,7 +102415,7 @@ const path_createPathTagFunction = (pathEncoder = path_encodeURIPath) => functio /** * URI-encodes path params and ensures no unsafe /./ or /../ path segments are introduced. */ -const path_path = /* @__PURE__ */ path_createPathTagFunction(path_encodeURIPath); +const utils_path_path = /* @__PURE__ */ path_createPathTagFunction(path_encodeURIPath); //# sourceMappingURL=path.mjs.map ;// CONCATENATED MODULE: ./node_modules/openai/resources/chat/completions/messages.mjs // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. @@ -104530,7 +102438,7 @@ class completions_messages_Messages extends resource_APIResource { * ``` */ list(completionID, query = {}, options) { - return this._client.getAPIList(path_path `/chat/completions/${completionID}/messages`, (CursorPage), { query, ...options }); + return this._client.getAPIList(utils_path_path `/chat/completions/${completionID}/messages`, (CursorPage), { query, ...options }); } } //# sourceMappingURL=messages.mjs.map @@ -106008,7 +103916,7 @@ class completions_Completions extends resource_APIResource { * ``` */ retrieve(completionID, options) { - return this._client.get(path_path `/chat/completions/${completionID}`, options); + return this._client.get(utils_path_path `/chat/completions/${completionID}`, options); } /** * Modify a stored chat completion. Only Chat Completions that have been created @@ -106024,7 +103932,7 @@ class completions_Completions extends resource_APIResource { * ``` */ update(completionID, body, options) { - return this._client.post(path_path `/chat/completions/${completionID}`, { body, ...options }); + return this._client.post(utils_path_path `/chat/completions/${completionID}`, { body, ...options }); } /** * List stored Chat Completions. Only Chat Completions that have been stored with @@ -106052,7 +103960,7 @@ class completions_Completions extends resource_APIResource { * ``` */ delete(completionID, options) { - return this._client.delete(path_path `/chat/completions/${completionID}`, options); + return this._client.delete(utils_path_path `/chat/completions/${completionID}`, options); } parse(body, options) { validateInputTools(body.tools); @@ -106276,7 +104184,7 @@ class resources_batches_Batches extends resource_APIResource { * Retrieves a batch. */ retrieve(batchID, options) { - return this._client.get(path_path `/batches/${batchID}`, options); + return this._client.get(utils_path_path `/batches/${batchID}`, options); } /** * List your organization's batches. @@ -106290,7 +104198,7 @@ class resources_batches_Batches extends resource_APIResource { * (if any) available in the output file. */ cancel(batchID, options) { - return this._client.post(path_path `/batches/${batchID}/cancel`, options); + return this._client.post(utils_path_path `/batches/${batchID}/cancel`, options); } } //# sourceMappingURL=batches.mjs.map @@ -106329,7 +104237,7 @@ class Assistants extends resource_APIResource { * ``` */ retrieve(assistantID, options) { - return this._client.get(path_path `/assistants/${assistantID}`, { + return this._client.get(utils_path_path `/assistants/${assistantID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -106345,7 +104253,7 @@ class Assistants extends resource_APIResource { * ``` */ update(assistantID, body, options) { - return this._client.post(path_path `/assistants/${assistantID}`, { + return this._client.post(utils_path_path `/assistants/${assistantID}`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -106379,7 +104287,7 @@ class Assistants extends resource_APIResource { * ``` */ delete(assistantID, options) { - return this._client.delete(path_path `/assistants/${assistantID}`, { + return this._client.delete(utils_path_path `/assistants/${assistantID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -106499,7 +104407,7 @@ class sessions_Sessions extends resource_APIResource { * ``` */ cancel(sessionID, options) { - return this._client.post(path_path `/chatkit/sessions/${sessionID}/cancel`, { + return this._client.post(utils_path_path `/chatkit/sessions/${sessionID}/cancel`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'chatkit_beta=v1' }, options?.headers]), }); @@ -106523,7 +104431,7 @@ class Threads extends resource_APIResource { * ``` */ retrieve(threadID, options) { - return this._client.get(path_path `/chatkit/threads/${threadID}`, { + return this._client.get(utils_path_path `/chatkit/threads/${threadID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'chatkit_beta=v1' }, options?.headers]), }); @@ -106557,7 +104465,7 @@ class Threads extends resource_APIResource { * ``` */ delete(threadID, options) { - return this._client.delete(path_path `/chatkit/threads/${threadID}`, { + return this._client.delete(utils_path_path `/chatkit/threads/${threadID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'chatkit_beta=v1' }, options?.headers]), }); @@ -106576,7 +104484,7 @@ class Threads extends resource_APIResource { * ``` */ listItems(threadID, query = {}, options) { - return this._client.getAPIList(path_path `/chatkit/threads/${threadID}/items`, (ConversationCursorPage), { query, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'chatkit_beta=v1' }, options?.headers]) }); + return this._client.getAPIList(utils_path_path `/chatkit/threads/${threadID}/items`, (ConversationCursorPage), { query, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'chatkit_beta=v1' }, options?.headers]) }); } } //# sourceMappingURL=threads.mjs.map @@ -106613,7 +104521,7 @@ class threads_messages_Messages extends resource_APIResource { * @deprecated The Assistants API is deprecated in favor of the Responses API */ create(threadID, body, options) { - return this._client.post(path_path `/threads/${threadID}/messages`, { + return this._client.post(utils_path_path `/threads/${threadID}/messages`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -106626,7 +104534,7 @@ class threads_messages_Messages extends resource_APIResource { */ retrieve(messageID, params, options) { const { thread_id } = params; - return this._client.get(path_path `/threads/${thread_id}/messages/${messageID}`, { + return this._client.get(utils_path_path `/threads/${thread_id}/messages/${messageID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -106638,7 +104546,7 @@ class threads_messages_Messages extends resource_APIResource { */ update(messageID, params, options) { const { thread_id, ...body } = params; - return this._client.post(path_path `/threads/${thread_id}/messages/${messageID}`, { + return this._client.post(utils_path_path `/threads/${thread_id}/messages/${messageID}`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -106650,7 +104558,7 @@ class threads_messages_Messages extends resource_APIResource { * @deprecated The Assistants API is deprecated in favor of the Responses API */ list(threadID, query = {}, options) { - return this._client.getAPIList(path_path `/threads/${threadID}/messages`, (CursorPage), { + return this._client.getAPIList(utils_path_path `/threads/${threadID}/messages`, (CursorPage), { query, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -106663,7 +104571,7 @@ class threads_messages_Messages extends resource_APIResource { */ delete(messageID, params, options) { const { thread_id } = params; - return this._client.delete(path_path `/threads/${thread_id}/messages/${messageID}`, { + return this._client.delete(utils_path_path `/threads/${thread_id}/messages/${messageID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -106687,7 +104595,7 @@ class Steps extends resource_APIResource { */ retrieve(stepID, params, options) { const { thread_id, run_id, ...query } = params; - return this._client.get(path_path `/threads/${thread_id}/runs/${run_id}/steps/${stepID}`, { + return this._client.get(utils_path_path `/threads/${thread_id}/runs/${run_id}/steps/${stepID}`, { query, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -106700,7 +104608,7 @@ class Steps extends resource_APIResource { */ list(runID, params, options) { const { thread_id, ...query } = params; - return this._client.getAPIList(path_path `/threads/${thread_id}/runs/${runID}/steps`, (CursorPage), { + return this._client.getAPIList(utils_path_path `/threads/${thread_id}/runs/${runID}/steps`, (CursorPage), { query, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -106712,7 +104620,7 @@ class Steps extends resource_APIResource { // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -const toBase64 = (data) => { +const base64_toBase64 = (data) => { if (!data) return ''; if (typeof globalThis.Buffer !== 'undefined') { @@ -106726,7 +104634,7 @@ const toBase64 = (data) => { } throw new OpenAIError('Cannot generate base64 string; Expected `Buffer` or `btoa` to be defined'); }; -const fromBase64 = (str) => { +const base64_fromBase64 = (str) => { if (typeof globalThis.Buffer !== 'undefined') { const buf = globalThis.Buffer.from(str, 'base64'); return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); @@ -107362,7 +105270,7 @@ class Runs extends resource_APIResource { } create(threadID, params, options) { const { include, ...body } = params; - return this._client.post(path_path `/threads/${threadID}/runs`, { + return this._client.post(utils_path_path `/threads/${threadID}/runs`, { query: { include }, body, ...options, @@ -107377,7 +105285,7 @@ class Runs extends resource_APIResource { */ retrieve(runID, params, options) { const { thread_id } = params; - return this._client.get(path_path `/threads/${thread_id}/runs/${runID}`, { + return this._client.get(utils_path_path `/threads/${thread_id}/runs/${runID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -107389,7 +105297,7 @@ class Runs extends resource_APIResource { */ update(runID, params, options) { const { thread_id, ...body } = params; - return this._client.post(path_path `/threads/${thread_id}/runs/${runID}`, { + return this._client.post(utils_path_path `/threads/${thread_id}/runs/${runID}`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -107401,7 +105309,7 @@ class Runs extends resource_APIResource { * @deprecated The Assistants API is deprecated in favor of the Responses API */ list(threadID, query = {}, options) { - return this._client.getAPIList(path_path `/threads/${threadID}/runs`, (CursorPage), { + return this._client.getAPIList(utils_path_path `/threads/${threadID}/runs`, (CursorPage), { query, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -107414,7 +105322,7 @@ class Runs extends resource_APIResource { */ cancel(runID, params, options) { const { thread_id } = params; - return this._client.post(path_path `/threads/${thread_id}/runs/${runID}/cancel`, { + return this._client.post(utils_path_path `/threads/${thread_id}/runs/${runID}/cancel`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -107493,7 +105401,7 @@ class Runs extends resource_APIResource { } submitToolOutputs(runID, params, options) { const { thread_id, ...body } = params; - return this._client.post(path_path `/threads/${thread_id}/runs/${runID}/submit_tool_outputs`, { + return this._client.post(utils_path_path `/threads/${thread_id}/runs/${runID}/submit_tool_outputs`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -107557,7 +105465,7 @@ class threads_Threads extends resource_APIResource { * @deprecated The Assistants API is deprecated in favor of the Responses API */ retrieve(threadID, options) { - return this._client.get(path_path `/threads/${threadID}`, { + return this._client.get(utils_path_path `/threads/${threadID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -107568,7 +105476,7 @@ class threads_Threads extends resource_APIResource { * @deprecated The Assistants API is deprecated in favor of the Responses API */ update(threadID, body, options) { - return this._client.post(path_path `/threads/${threadID}`, { + return this._client.post(utils_path_path `/threads/${threadID}`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -107580,7 +105488,7 @@ class threads_Threads extends resource_APIResource { * @deprecated The Assistants API is deprecated in favor of the Responses API */ delete(threadID, options) { - return this._client.delete(path_path `/threads/${threadID}`, { + return this._client.delete(utils_path_path `/threads/${threadID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -107657,7 +105565,7 @@ class Content extends resource_APIResource { */ retrieve(fileID, params, options) { const { container_id } = params; - return this._client.get(path_path `/containers/${container_id}/files/${fileID}/content`, { + return this._client.get(utils_path_path `/containers/${container_id}/files/${fileID}/content`, { ...options, headers: headers_buildHeaders([{ Accept: 'application/binary' }, options?.headers]), __binaryResponse: true, @@ -107686,20 +105594,20 @@ class files_Files extends resource_APIResource { * a JSON request with a file ID. */ create(containerID, body, options) { - return this._client.post(path_path `/containers/${containerID}/files`, uploads_multipartFormRequestOptions({ body, ...options }, this._client)); + return this._client.post(utils_path_path `/containers/${containerID}/files`, uploads_multipartFormRequestOptions({ body, ...options }, this._client)); } /** * Retrieve Container File */ retrieve(fileID, params, options) { const { container_id } = params; - return this._client.get(path_path `/containers/${container_id}/files/${fileID}`, options); + return this._client.get(utils_path_path `/containers/${container_id}/files/${fileID}`, options); } /** * List Container files */ list(containerID, query = {}, options) { - return this._client.getAPIList(path_path `/containers/${containerID}/files`, (CursorPage), { + return this._client.getAPIList(utils_path_path `/containers/${containerID}/files`, (CursorPage), { query, ...options, }); @@ -107709,7 +105617,7 @@ class files_Files extends resource_APIResource { */ delete(fileID, params, options) { const { container_id } = params; - return this._client.delete(path_path `/containers/${container_id}/files/${fileID}`, { + return this._client.delete(utils_path_path `/containers/${container_id}/files/${fileID}`, { ...options, headers: headers_buildHeaders([{ Accept: '*/*' }, options?.headers]), }); @@ -107740,7 +105648,7 @@ class Containers extends resource_APIResource { * Retrieve Container */ retrieve(containerID, options) { - return this._client.get(path_path `/containers/${containerID}`, options); + return this._client.get(utils_path_path `/containers/${containerID}`, options); } /** * List Containers @@ -107752,7 +105660,7 @@ class Containers extends resource_APIResource { * Delete Container */ delete(containerID, options) { - return this._client.delete(path_path `/containers/${containerID}`, { + return this._client.delete(utils_path_path `/containers/${containerID}`, { ...options, headers: headers_buildHeaders([{ Accept: '*/*' }, options?.headers]), }); @@ -107771,7 +105679,7 @@ class Items extends resource_APIResource { */ create(conversationID, params, options) { const { include, ...body } = params; - return this._client.post(path_path `/conversations/${conversationID}/items`, { + return this._client.post(utils_path_path `/conversations/${conversationID}/items`, { query: { include }, body, ...options, @@ -107782,20 +105690,20 @@ class Items extends resource_APIResource { */ retrieve(itemID, params, options) { const { conversation_id, ...query } = params; - return this._client.get(path_path `/conversations/${conversation_id}/items/${itemID}`, { query, ...options }); + return this._client.get(utils_path_path `/conversations/${conversation_id}/items/${itemID}`, { query, ...options }); } /** * List all items for a conversation with the given ID. */ list(conversationID, query = {}, options) { - return this._client.getAPIList(path_path `/conversations/${conversationID}/items`, (ConversationCursorPage), { query, ...options }); + return this._client.getAPIList(utils_path_path `/conversations/${conversationID}/items`, (ConversationCursorPage), { query, ...options }); } /** * Delete an item from a conversation with the given IDs. */ delete(itemID, params, options) { const { conversation_id } = params; - return this._client.delete(path_path `/conversations/${conversation_id}/items/${itemID}`, options); + return this._client.delete(utils_path_path `/conversations/${conversation_id}/items/${itemID}`, options); } } //# sourceMappingURL=items.mjs.map @@ -107820,19 +105728,19 @@ class Conversations extends resource_APIResource { * Get a conversation */ retrieve(conversationID, options) { - return this._client.get(path_path `/conversations/${conversationID}`, options); + return this._client.get(utils_path_path `/conversations/${conversationID}`, options); } /** * Update a conversation */ update(conversationID, body, options) { - return this._client.post(path_path `/conversations/${conversationID}`, { body, ...options }); + return this._client.post(utils_path_path `/conversations/${conversationID}`, { body, ...options }); } /** * Delete a conversation. Items in the conversation will not be deleted. */ delete(conversationID, options) { - return this._client.delete(path_path `/conversations/${conversationID}`, options); + return this._client.delete(utils_path_path `/conversations/${conversationID}`, options); } } Conversations.Items = Items; @@ -107901,14 +105809,14 @@ class OutputItems extends resource_APIResource { */ retrieve(outputItemID, params, options) { const { eval_id, run_id } = params; - return this._client.get(path_path `/evals/${eval_id}/runs/${run_id}/output_items/${outputItemID}`, options); + return this._client.get(utils_path_path `/evals/${eval_id}/runs/${run_id}/output_items/${outputItemID}`, options); } /** * Get a list of output items for an evaluation run. */ list(runID, params, options) { const { eval_id, ...query } = params; - return this._client.getAPIList(path_path `/evals/${eval_id}/runs/${runID}/output_items`, (CursorPage), { query, ...options }); + return this._client.getAPIList(utils_path_path `/evals/${eval_id}/runs/${runID}/output_items`, (CursorPage), { query, ...options }); } } //# sourceMappingURL=output-items.mjs.map @@ -107930,20 +105838,20 @@ class runs_Runs extends resource_APIResource { * schema specified in the config of the evaluation. */ create(evalID, body, options) { - return this._client.post(path_path `/evals/${evalID}/runs`, { body, ...options }); + return this._client.post(utils_path_path `/evals/${evalID}/runs`, { body, ...options }); } /** * Get an evaluation run by ID. */ retrieve(runID, params, options) { const { eval_id } = params; - return this._client.get(path_path `/evals/${eval_id}/runs/${runID}`, options); + return this._client.get(utils_path_path `/evals/${eval_id}/runs/${runID}`, options); } /** * Get a list of runs for an evaluation. */ list(evalID, query = {}, options) { - return this._client.getAPIList(path_path `/evals/${evalID}/runs`, (CursorPage), { + return this._client.getAPIList(utils_path_path `/evals/${evalID}/runs`, (CursorPage), { query, ...options, }); @@ -107953,14 +105861,14 @@ class runs_Runs extends resource_APIResource { */ delete(runID, params, options) { const { eval_id } = params; - return this._client.delete(path_path `/evals/${eval_id}/runs/${runID}`, options); + return this._client.delete(utils_path_path `/evals/${eval_id}/runs/${runID}`, options); } /** * Cancel an ongoing evaluation run. */ cancel(runID, params, options) { const { eval_id } = params; - return this._client.post(path_path `/evals/${eval_id}/runs/${runID}`, options); + return this._client.post(utils_path_path `/evals/${eval_id}/runs/${runID}`, options); } } runs_Runs.OutputItems = OutputItems; @@ -107992,13 +105900,13 @@ class Evals extends resource_APIResource { * Get an evaluation by ID. */ retrieve(evalID, options) { - return this._client.get(path_path `/evals/${evalID}`, options); + return this._client.get(utils_path_path `/evals/${evalID}`, options); } /** * Update certain properties of an evaluation. */ update(evalID, body, options) { - return this._client.post(path_path `/evals/${evalID}`, { body, ...options }); + return this._client.post(utils_path_path `/evals/${evalID}`, { body, ...options }); } /** * List evaluations for a project. @@ -108010,7 +105918,7 @@ class Evals extends resource_APIResource { * Delete an evaluation. */ delete(evalID, options) { - return this._client.delete(path_path `/evals/${evalID}`, options); + return this._client.delete(utils_path_path `/evals/${evalID}`, options); } } Evals.Runs = runs_Runs; @@ -108054,7 +105962,7 @@ class resources_files_Files extends resource_APIResource { * Returns information about a specific file. */ retrieve(fileID, options) { - return this._client.get(path_path `/files/${fileID}`, options); + return this._client.get(utils_path_path `/files/${fileID}`, options); } /** * Returns a list of files. @@ -108066,13 +105974,13 @@ class resources_files_Files extends resource_APIResource { * Delete a file and remove it from all vector stores. */ delete(fileID, options) { - return this._client.delete(path_path `/files/${fileID}`, options); + return this._client.delete(utils_path_path `/files/${fileID}`, options); } /** * Returns the contents of the specified file. */ content(fileID, options) { - return this._client.get(path_path `/files/${fileID}/content`, { + return this._client.get(utils_path_path `/files/${fileID}/content`, { ...options, headers: headers_buildHeaders([{ Accept: 'application/binary' }, options?.headers]), __binaryResponse: true, @@ -108187,7 +106095,7 @@ class Permissions extends resource_APIResource { * ``` */ create(fineTunedModelCheckpoint, body, options) { - return this._client.getAPIList(path_path `/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`, (pagination_Page), { body, method: 'post', ...options }); + return this._client.getAPIList(utils_path_path `/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`, (pagination_Page), { body, method: 'post', ...options }); } /** * **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). @@ -108204,7 +106112,7 @@ class Permissions extends resource_APIResource { * ``` */ retrieve(fineTunedModelCheckpoint, query = {}, options) { - return this._client.get(path_path `/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`, { + return this._client.get(utils_path_path `/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`, { query, ...options, }); @@ -108229,7 +106137,7 @@ class Permissions extends resource_APIResource { */ delete(permissionID, params, options) { const { fine_tuned_model_checkpoint } = params; - return this._client.delete(path_path `/fine_tuning/checkpoints/${fine_tuned_model_checkpoint}/permissions/${permissionID}`, options); + return this._client.delete(utils_path_path `/fine_tuning/checkpoints/${fine_tuned_model_checkpoint}/permissions/${permissionID}`, options); } } //# sourceMappingURL=permissions.mjs.map @@ -108266,7 +106174,7 @@ class checkpoints_Checkpoints extends resource_APIResource { * ``` */ list(fineTuningJobID, query = {}, options) { - return this._client.getAPIList(path_path `/fine_tuning/jobs/${fineTuningJobID}/checkpoints`, (CursorPage), { query, ...options }); + return this._client.getAPIList(utils_path_path `/fine_tuning/jobs/${fineTuningJobID}/checkpoints`, (CursorPage), { query, ...options }); } } //# sourceMappingURL=checkpoints.mjs.map @@ -108315,7 +106223,7 @@ class Jobs extends resource_APIResource { * ``` */ retrieve(fineTuningJobID, options) { - return this._client.get(path_path `/fine_tuning/jobs/${fineTuningJobID}`, options); + return this._client.get(utils_path_path `/fine_tuning/jobs/${fineTuningJobID}`, options); } /** * List your organization's fine-tuning jobs @@ -108342,7 +106250,7 @@ class Jobs extends resource_APIResource { * ``` */ cancel(fineTuningJobID, options) { - return this._client.post(path_path `/fine_tuning/jobs/${fineTuningJobID}/cancel`, options); + return this._client.post(utils_path_path `/fine_tuning/jobs/${fineTuningJobID}/cancel`, options); } /** * Get status updates for a fine-tuning job. @@ -108358,7 +106266,7 @@ class Jobs extends resource_APIResource { * ``` */ listEvents(fineTuningJobID, query = {}, options) { - return this._client.getAPIList(path_path `/fine_tuning/jobs/${fineTuningJobID}/events`, (CursorPage), { query, ...options }); + return this._client.getAPIList(utils_path_path `/fine_tuning/jobs/${fineTuningJobID}/events`, (CursorPage), { query, ...options }); } /** * Pause a fine-tune job. @@ -108371,7 +106279,7 @@ class Jobs extends resource_APIResource { * ``` */ pause(fineTuningJobID, options) { - return this._client.post(path_path `/fine_tuning/jobs/${fineTuningJobID}/pause`, options); + return this._client.post(utils_path_path `/fine_tuning/jobs/${fineTuningJobID}/pause`, options); } /** * Resume a fine-tune job. @@ -108384,7 +106292,7 @@ class Jobs extends resource_APIResource { * ``` */ resume(fineTuningJobID, options) { - return this._client.post(path_path `/fine_tuning/jobs/${fineTuningJobID}/resume`, options); + return this._client.post(utils_path_path `/fine_tuning/jobs/${fineTuningJobID}/resume`, options); } } Jobs.Checkpoints = checkpoints_Checkpoints; @@ -108470,7 +106378,7 @@ class resources_models_Models extends resource_APIResource { * the owner and permissioning. */ retrieve(model, options) { - return this._client.get(path_path `/models/${model}`, options); + return this._client.get(utils_path_path `/models/${model}`, options); } /** * Lists the currently available models, and provides basic information about each @@ -108484,7 +106392,7 @@ class resources_models_Models extends resource_APIResource { * delete a model. */ delete(model, options) { - return this._client.delete(path_path `/models/${model}`, options); + return this._client.delete(utils_path_path `/models/${model}`, options); } } //# sourceMappingURL=models.mjs.map @@ -108519,7 +106427,7 @@ class Calls extends resource_APIResource { * ``` */ accept(callID, body, options) { - return this._client.post(path_path `/realtime/calls/${callID}/accept`, { + return this._client.post(utils_path_path `/realtime/calls/${callID}/accept`, { body, ...options, headers: headers_buildHeaders([{ Accept: '*/*' }, options?.headers]), @@ -108534,7 +106442,7 @@ class Calls extends resource_APIResource { * ``` */ hangup(callID, options) { - return this._client.post(path_path `/realtime/calls/${callID}/hangup`, { + return this._client.post(utils_path_path `/realtime/calls/${callID}/hangup`, { ...options, headers: headers_buildHeaders([{ Accept: '*/*' }, options?.headers]), }); @@ -108550,7 +106458,7 @@ class Calls extends resource_APIResource { * ``` */ refer(callID, body, options) { - return this._client.post(path_path `/realtime/calls/${callID}/refer`, { + return this._client.post(utils_path_path `/realtime/calls/${callID}/refer`, { body, ...options, headers: headers_buildHeaders([{ Accept: '*/*' }, options?.headers]), @@ -108565,7 +106473,7 @@ class Calls extends resource_APIResource { * ``` */ reject(callID, body = {}, options) { - return this._client.post(path_path `/realtime/calls/${callID}/reject`, { + return this._client.post(utils_path_path `/realtime/calls/${callID}/reject`, { body, ...options, headers: headers_buildHeaders([{ Accept: '*/*' }, options?.headers]), @@ -109051,7 +106959,7 @@ class InputItems extends resource_APIResource { * ``` */ list(responseID, query = {}, options) { - return this._client.getAPIList(path_path `/responses/${responseID}/input_items`, (CursorPage), { query, ...options }); + return this._client.getAPIList(utils_path_path `/responses/${responseID}/input_items`, (CursorPage), { query, ...options }); } } //# sourceMappingURL=input-items.mjs.map @@ -109098,7 +107006,7 @@ class Responses extends resource_APIResource { }); } retrieve(responseID, query = {}, options) { - return this._client.get(path_path `/responses/${responseID}`, { + return this._client.get(utils_path_path `/responses/${responseID}`, { query, ...options, stream: query?.stream ?? false, @@ -109120,7 +107028,7 @@ class Responses extends resource_APIResource { * ``` */ delete(responseID, options) { - return this._client.delete(path_path `/responses/${responseID}`, { + return this._client.delete(utils_path_path `/responses/${responseID}`, { ...options, headers: headers_buildHeaders([{ Accept: '*/*' }, options?.headers]), }); @@ -109149,7 +107057,20 @@ class Responses extends resource_APIResource { * ``` */ cancel(responseID, options) { - return this._client.post(path_path `/responses/${responseID}/cancel`, options); + return this._client.post(utils_path_path `/responses/${responseID}/cancel`, options); + } + /** + * Compact conversation + * + * @example + * ```ts + * const compactedResponse = await client.responses.compact({ + * model: 'gpt-5.2', + * }); + * ``` + */ + compact(body, options) { + return this._client.post('/responses/compact', { body, ...options }); } } Responses.InputItems = InputItems; @@ -109175,7 +107096,7 @@ class Parts extends resource_APIResource { * [complete the Upload](https://platform.openai.com/docs/api-reference/uploads/complete). */ create(uploadID, body, options) { - return this._client.post(path_path `/uploads/${uploadID}/parts`, uploads_multipartFormRequestOptions({ body, ...options }, this._client)); + return this._client.post(utils_path_path `/uploads/${uploadID}/parts`, uploads_multipartFormRequestOptions({ body, ...options }, this._client)); } } //# sourceMappingURL=parts.mjs.map @@ -109218,7 +107139,7 @@ class Uploads extends resource_APIResource { * Cancels the Upload. No Parts may be added after an Upload is cancelled. */ cancel(uploadID, options) { - return this._client.post(path_path `/uploads/${uploadID}/cancel`, options); + return this._client.post(utils_path_path `/uploads/${uploadID}/cancel`, options); } /** * Completes the @@ -109236,7 +107157,7 @@ class Uploads extends resource_APIResource { * an Upload is completed. */ complete(uploadID, body, options) { - return this._client.post(path_path `/uploads/${uploadID}/complete`, { body, ...options }); + return this._client.post(utils_path_path `/uploads/${uploadID}/complete`, { body, ...options }); } } Uploads.Parts = Parts; @@ -109277,7 +107198,7 @@ class FileBatches extends resource_APIResource { * Create a vector store file batch. */ create(vectorStoreID, body, options) { - return this._client.post(path_path `/vector_stores/${vectorStoreID}/file_batches`, { + return this._client.post(utils_path_path `/vector_stores/${vectorStoreID}/file_batches`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -109288,7 +107209,7 @@ class FileBatches extends resource_APIResource { */ retrieve(batchID, params, options) { const { vector_store_id } = params; - return this._client.get(path_path `/vector_stores/${vector_store_id}/file_batches/${batchID}`, { + return this._client.get(utils_path_path `/vector_stores/${vector_store_id}/file_batches/${batchID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -109299,7 +107220,7 @@ class FileBatches extends resource_APIResource { */ cancel(batchID, params, options) { const { vector_store_id } = params; - return this._client.post(path_path `/vector_stores/${vector_store_id}/file_batches/${batchID}/cancel`, { + return this._client.post(utils_path_path `/vector_stores/${vector_store_id}/file_batches/${batchID}/cancel`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -109316,7 +107237,7 @@ class FileBatches extends resource_APIResource { */ listFiles(batchID, params, options) { const { vector_store_id, ...query } = params; - return this._client.getAPIList(path_path `/vector_stores/${vector_store_id}/file_batches/${batchID}/files`, (CursorPage), { query, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]) }); + return this._client.getAPIList(utils_path_path `/vector_stores/${vector_store_id}/file_batches/${batchID}/files`, (CursorPage), { query, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]) }); } /** * Wait for the given file batch to be processed. @@ -109408,7 +107329,7 @@ class vector_stores_files_Files extends resource_APIResource { * [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object). */ create(vectorStoreID, body, options) { - return this._client.post(path_path `/vector_stores/${vectorStoreID}/files`, { + return this._client.post(utils_path_path `/vector_stores/${vectorStoreID}/files`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -109419,7 +107340,7 @@ class vector_stores_files_Files extends resource_APIResource { */ retrieve(fileID, params, options) { const { vector_store_id } = params; - return this._client.get(path_path `/vector_stores/${vector_store_id}/files/${fileID}`, { + return this._client.get(utils_path_path `/vector_stores/${vector_store_id}/files/${fileID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -109429,7 +107350,7 @@ class vector_stores_files_Files extends resource_APIResource { */ update(fileID, params, options) { const { vector_store_id, ...body } = params; - return this._client.post(path_path `/vector_stores/${vector_store_id}/files/${fileID}`, { + return this._client.post(utils_path_path `/vector_stores/${vector_store_id}/files/${fileID}`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -109439,7 +107360,7 @@ class vector_stores_files_Files extends resource_APIResource { * Returns a list of vector store files. */ list(vectorStoreID, query = {}, options) { - return this._client.getAPIList(path_path `/vector_stores/${vectorStoreID}/files`, (CursorPage), { + return this._client.getAPIList(utils_path_path `/vector_stores/${vectorStoreID}/files`, (CursorPage), { query, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -109453,7 +107374,7 @@ class vector_stores_files_Files extends resource_APIResource { */ delete(fileID, params, options) { const { vector_store_id } = params; - return this._client.delete(path_path `/vector_stores/${vector_store_id}/files/${fileID}`, { + return this._client.delete(utils_path_path `/vector_stores/${vector_store_id}/files/${fileID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -109529,7 +107450,7 @@ class vector_stores_files_Files extends resource_APIResource { */ content(fileID, params, options) { const { vector_store_id } = params; - return this._client.getAPIList(path_path `/vector_stores/${vector_store_id}/files/${fileID}/content`, (pagination_Page), { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]) }); + return this._client.getAPIList(utils_path_path `/vector_stores/${vector_store_id}/files/${fileID}/content`, (pagination_Page), { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]) }); } } //# sourceMappingURL=files.mjs.map @@ -109563,7 +107484,7 @@ class VectorStores extends resource_APIResource { * Retrieves a vector store. */ retrieve(vectorStoreID, options) { - return this._client.get(path_path `/vector_stores/${vectorStoreID}`, { + return this._client.get(utils_path_path `/vector_stores/${vectorStoreID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -109572,7 +107493,7 @@ class VectorStores extends resource_APIResource { * Modifies a vector store. */ update(vectorStoreID, body, options) { - return this._client.post(path_path `/vector_stores/${vectorStoreID}`, { + return this._client.post(utils_path_path `/vector_stores/${vectorStoreID}`, { body, ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), @@ -109592,7 +107513,7 @@ class VectorStores extends resource_APIResource { * Delete a vector store. */ delete(vectorStoreID, options) { - return this._client.delete(path_path `/vector_stores/${vectorStoreID}`, { + return this._client.delete(utils_path_path `/vector_stores/${vectorStoreID}`, { ...options, headers: headers_buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); @@ -109602,7 +107523,7 @@ class VectorStores extends resource_APIResource { * filter. */ search(vectorStoreID, body, options) { - return this._client.getAPIList(path_path `/vector_stores/${vectorStoreID}/search`, (pagination_Page), { + return this._client.getAPIList(utils_path_path `/vector_stores/${vectorStoreID}/search`, (pagination_Page), { body, method: 'post', ...options, @@ -109631,7 +107552,7 @@ class Videos extends resource_APIResource { * Retrieve a video */ retrieve(videoID, options) { - return this._client.get(path_path `/videos/${videoID}`, options); + return this._client.get(utils_path_path `/videos/${videoID}`, options); } /** * List videos @@ -109643,13 +107564,13 @@ class Videos extends resource_APIResource { * Delete a video */ delete(videoID, options) { - return this._client.delete(path_path `/videos/${videoID}`, options); + return this._client.delete(utils_path_path `/videos/${videoID}`, options); } /** * Download video content */ downloadContent(videoID, query = {}, options) { - return this._client.get(path_path `/videos/${videoID}/content`, { + return this._client.get(utils_path_path `/videos/${videoID}/content`, { query, ...options, headers: headers_buildHeaders([{ Accept: 'application/binary' }, options?.headers]), @@ -109660,7 +107581,7 @@ class Videos extends resource_APIResource { * Create a video remix */ remix(videoID, body, options) { - return this._client.post(path_path `/videos/${videoID}/remix`, uploads_maybeMultipartFormRequestOptions({ body, ...options }, this._client)); + return this._client.post(utils_path_path `/videos/${videoID}/remix`, uploads_maybeMultipartFormRequestOptions({ body, ...options }, this._client)); } } //# sourceMappingURL=videos.mjs.map @@ -109789,7 +107710,7 @@ _Webhooks_instances = new WeakSet(), _Webhooks_validateSecret = function _Webhoo //# sourceMappingURL=index.mjs.map ;// CONCATENATED MODULE: ./node_modules/openai/client.mjs // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -var _OpenAI_instances, openai_client_a, _OpenAI_encoder, _OpenAI_baseURLOverridden; +var _OpenAI_instances, client_a, _OpenAI_encoder, _OpenAI_baseURLOverridden; @@ -109890,7 +107811,7 @@ class OpenAI { throw new error_OpenAIError("It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n"); } this.baseURL = options.baseURL; - this.timeout = options.timeout ?? openai_client_a.DEFAULT_TIMEOUT /* 10 minutes */; + this.timeout = options.timeout ?? client_a.DEFAULT_TIMEOUT /* 10 minutes */; this.logger = options.logger ?? console; const defaultLogLevel = 'warn'; // Set default logLevel early so that we can log a warning in parseLogLevel. @@ -110305,10 +108226,10 @@ class OpenAI { } } } -openai_client_a = OpenAI, _OpenAI_encoder = new WeakMap(), _OpenAI_instances = new WeakSet(), _OpenAI_baseURLOverridden = function _OpenAI_baseURLOverridden() { +client_a = OpenAI, _OpenAI_encoder = new WeakMap(), _OpenAI_instances = new WeakSet(), _OpenAI_baseURLOverridden = function _OpenAI_baseURLOverridden() { return this.baseURL !== 'https://api.openai.com/v1'; }; -OpenAI.OpenAI = openai_client_a; +OpenAI.OpenAI = client_a; OpenAI.DEFAULT_TIMEOUT = 600000; // 10 minutes OpenAI.OpenAIError = error_OpenAIError; OpenAI.APIError = error_APIError; @@ -110490,6 +108411,11 @@ function extractGenericMessageCustomRole(message) { if (message.role !== "system" && message.role !== "developer" && message.role !== "assistant" && message.role !== "user" && message.role !== "function" && message.role !== "tool") console.warn(`Unknown message role: ${message.role}`); return message.role; } +function getRequiredFilenameFromMetadata(block) { + const filename = block.metadata?.filename ?? block.metadata?.name ?? block.metadata?.title; + if (!filename) throw new Error("a filename or name or title is needed via meta-data for OpenAI when working with multimodal blocks"); + return filename; +} function messageToOpenAIRole(message) { const type = message._getType(); switch (type) { @@ -110504,6 +108430,9 @@ function messageToOpenAIRole(message) { default: throw new Error(`Unknown message type: ${type}`); } } +function _modelPrefersResponsesAPI(model) { + return model.includes("gpt-5.2-pro"); +} //#endregion @@ -110700,6 +108629,14 @@ function formatToOpenAIToolChoice(toolChoice) { function isBuiltInTool(tool) { return "type" in tool && tool.type !== "function"; } +/** +* Checks if a tool has a provider-specific tool definition in extras.providerToolDefinition. +* This is used for tools like localShell, shell, computerUse, and applyPatch +* that need to be sent as built-in tool types to the OpenAI API. +*/ +function hasProviderToolDefinition(tool) { + return typeof tool === "object" && tool !== null && "extras" in tool && typeof tool.extras === "object" && tool.extras !== null && "providerToolDefinition" in tool.extras && typeof tool.extras.providerToolDefinition === "object" && tool.extras.providerToolDefinition !== null; +} function isBuiltInToolChoice(tool_choice) { return tool_choice != null && typeof tool_choice === "object" && "type" in tool_choice && tool_choice.type !== "function"; } @@ -110721,8 +108658,35 @@ function parseCustomToolCall(rawToolCall) { args: { input: rawToolCall.input } }; } +/** +* Parses a computer_call output item from the OpenAI Responses API +* into a ToolCall format that can be processed by the ToolNode. +* +* @param rawToolCall - The raw computer_call output item from the API +* @returns A ComputerToolCall object if valid, undefined otherwise +*/ +function parseComputerCall(rawToolCall) { + if (rawToolCall.type !== "computer_call") return void 0; + return { + ...rawToolCall, + type: "tool_call", + call_id: rawToolCall.id, + id: rawToolCall.call_id, + name: "computer_use", + isComputerTool: true, + args: { action: rawToolCall.action } + }; +} +/** +* Checks if a tool call is a computer tool call. +* @param toolCall - The tool call to check. +* @returns True if the tool call is a computer tool call, false otherwise. +*/ +function isComputerToolCall(toolCall) { + return typeof toolCall === "object" && toolCall !== null && "type" in toolCall && toolCall.type === "tool_call" && "isComputerTool" in toolCall && toolCall.isComputerTool === true; +} function isCustomToolCall(toolCall) { - return toolCall.type === "tool_call" && "isCustomTool" in toolCall && toolCall.isCustomTool === true; + return typeof toolCall === "object" && toolCall !== null && "type" in toolCall && toolCall.type === "tool_call" && "isCustomTool" in toolCall && toolCall.isCustomTool === true; } function convertCompletionsCustomTool(tool) { const getFormat = () => { @@ -112448,6 +110412,7 @@ function zodResponsesFunction(options) { + //#region src/utils/output.ts const SUPPORTED_METHODS = [ "jsonSchema", @@ -112501,7 +110466,7 @@ function interopZodResponseFormat(zodSchema, name, props) { ...props, name, strict: true, - schema: toJSONSchema(zodSchema, { + schema: toJsonSchema(zodSchema, { cycles: "ref", reused: "ref", override(ctx) { @@ -113123,6 +111088,7 @@ var profiles_profiles_default = profiles_PROFILES; + //#region src/chat_models/base.ts /** @internal */ var BaseChatOpenAI = class extends BaseChatModel { @@ -113182,6 +111148,10 @@ var BaseChatOpenAI = class extends BaseChatModel { */ promptCacheKey; /** + * Used by OpenAI to set cache retention time + */ + promptCacheRetention; + /** * The verbosity of the model's response. */ verbosity; @@ -113257,6 +111227,7 @@ var BaseChatOpenAI = class extends BaseChatModel { "zdrEnabled", "reasoning", "promptCacheKey", + "promptCacheRetention", "verbosity" ]; } @@ -113310,6 +111281,7 @@ var BaseChatOpenAI = class extends BaseChatModel { this.reasoning = fields?.reasoning; this.maxTokens = fields?.maxCompletionTokens ?? fields?.maxTokens; this.promptCacheKey = fields?.promptCacheKey ?? this.promptCacheKey; + this.promptCacheRetention = fields?.promptCacheRetention ?? this.promptCacheRetention; this.verbosity = fields?.verbosity ?? this.verbosity; this.disableStreaming = fields?.disableStreaming === true; this.streaming = fields?.streaming === true; @@ -113398,7 +111370,11 @@ var BaseChatOpenAI = class extends BaseChatModel { if (kwargs?.strict !== void 0) strict = kwargs.strict; else if (this.supportsStrictToolCalling !== void 0) strict = this.supportsStrictToolCalling; return this.withConfig({ - tools: tools.map((tool) => isBuiltInTool(tool) || isCustomTool(tool) ? tool : this._convertChatOpenAIToolToCompletionsTool(tool, { strict })), + tools: tools.map((tool) => { + if (isBuiltInTool(tool) || isCustomTool(tool)) return tool; + if (hasProviderToolDefinition(tool)) return tool.extras.providerToolDefinition; + return this._convertChatOpenAIToolToCompletionsTool(tool, { strict }); + }), ...kwargs }); } @@ -113480,6 +111456,61 @@ var BaseChatOpenAI = class extends BaseChatModel { return tokens; } /** + * Moderate content using OpenAI's Moderation API. + * + * This method checks whether content violates OpenAI's content policy by + * analyzing text for categories such as hate, harassment, self-harm, + * sexual content, violence, and more. + * + * @param input - The text or array of texts to moderate + * @param params - Optional parameters for the moderation request + * @param params.model - The moderation model to use. Defaults to "omni-moderation-latest". + * @param params.options - Additional options to pass to the underlying request + * @returns A promise that resolves to the moderation response containing results for each input + * + * @example + * ```typescript + * const model = new ChatOpenAI({ model: "gpt-4o-mini" }); + * + * // Moderate a single text + * const result = await model.moderateContent("This is a test message"); + * console.log(result.results[0].flagged); // false + * console.log(result.results[0].categories); // { hate: false, harassment: false, ... } + * + * // Moderate multiple texts + * const results = await model.moderateContent([ + * "Hello, how are you?", + * "This is inappropriate content" + * ]); + * results.results.forEach((result, index) => { + * console.log(`Text ${index + 1} flagged:`, result.flagged); + * }); + * + * // Use a specific moderation model + * const stableResult = await model.moderateContent( + * "Test content", + * { model: "omni-moderation-latest" } + * ); + * ``` + */ + async moderateContent(input, params) { + const clientOptions = this._getClientOptions(params?.options); + const moderationModel = params?.model ?? "omni-moderation-latest"; + const moderationRequest = { + input, + model: moderationModel + }; + return this.caller.call(async () => { + try { + const response = await this.client.moderations.create(moderationRequest, clientOptions); + return response; + } catch (e) { + const error = wrapOpenAIClientError(e); + throw error; + } + }); + } + /** * Return profiling information for the model. * * Provides information about the model's capabilities and constraints, @@ -113741,22 +111772,26 @@ const completionsApiContentBlockConverter = { fromStandardFileBlock(block) { if (block.source_type === "url") { const data = parseBase64DataUrl({ dataUrl: block.url }); + const filename = getRequiredFilenameFromMetadata(block); if (!data) throw new Error(`URL file blocks with source_type ${block.source_type} must be formatted as a data URL for ChatOpenAI`); return { type: "file", file: { file_data: block.url, - ...block.metadata?.filename || block.metadata?.name ? { filename: block.metadata?.filename || block.metadata?.name } : {} + ...block.metadata?.filename || block.metadata?.name ? { filename } : {} + } + }; + } + if (block.source_type === "base64") { + const filename = getRequiredFilenameFromMetadata(block); + return { + type: "file", + file: { + file_data: `data:${block.mime_type ?? ""};base64,${block.data}`, + ...block.metadata?.filename || block.metadata?.name || block.metadata?.title ? { filename } : {} } }; } - if (block.source_type === "base64") return { - type: "file", - file: { - file_data: `data:${block.mime_type ?? ""};base64,${block.data}`, - ...block.metadata?.filename || block.metadata?.name || block.metadata?.title ? { filename: block.metadata?.filename || block.metadata?.name || block.metadata?.title } : {} - } - }; if (block.source_type === "id") return { type: "file", file: { file_id: block.id } @@ -114036,10 +112071,16 @@ const convertStandardContentBlockToCompletionsContentPart = (block) => { } } if (block.type === "file") { - if (block.data) return { - type: "file", - file: { file_data: block.data.toString() } - }; + if (block.data) { + const filename = getRequiredFilenameFromMetadata(block); + return { + type: "file", + file: { + file_data: `data:${block.mimeType};base64,${block.data}`, + filename + } + }; + } if (block.fileId) return { type: "file", file: { file_id: block.fileId } @@ -114237,14 +112278,9 @@ const completions_convertMessagesToCompletionsMessageParams = ({ messages, model content }; if (message.name != null) completionParam.name = message.name; - if (message.additional_kwargs.function_call != null) { - completionParam.function_call = message.additional_kwargs.function_call; - completionParam.content = ""; - } - if (AIMessage.isInstance(message) && !!message.tool_calls?.length) { - completionParam.tool_calls = message.tool_calls.map(convertLangChainToolCallToOpenAI); - completionParam.content = ""; - } else { + if (message.additional_kwargs.function_call != null) completionParam.function_call = message.additional_kwargs.function_call; + if (AIMessage.isInstance(message) && !!message.tool_calls?.length) completionParam.tool_calls = message.tool_calls.map(convertLangChainToolCallToOpenAI); + else { if (message.additional_kwargs.tool_calls != null) completionParam.tool_calls = message.additional_kwargs.tool_calls; if (ToolMessage.isInstance(message) && message.tool_call_id != null) completionParam.tool_call_id = message.tool_call_id; } @@ -114310,6 +112346,7 @@ var ChatOpenAICompletions = class extends BaseChatOpenAI { ...this.modalities || options?.modalities ? { modalities: this.modalities || options?.modalities } : {}, ...this.modelKwargs, prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey, + prompt_cache_retention: options?.promptCacheRetention ?? this.promptCacheRetention, verbosity: options?.verbosity ?? this.verbosity }; if (options?.prediction !== void 0) params.prediction = options.prediction; @@ -114874,6 +112911,10 @@ const convertResponsesMessageToAIMessage = (response) => { const parsed = parseCustomToolCall(item); if (parsed) tool_calls.push(parsed); else invalid_tool_calls.push(makeInvalidToolCall(item, "Malformed custom tool call")); + } else if (item.type === "computer_call") { + const parsed = parseComputerCall(item); + if (parsed) tool_calls.push(parsed); + else invalid_tool_calls.push(makeInvalidToolCall(item, "Malformed computer call")); } else { additional_kwargs.tool_outputs ??= []; additional_kwargs.tool_outputs.push(item); @@ -115043,10 +113084,18 @@ const convertResponsesDeltaToChatGenerationChunk = (event) => { index: event.output_index }); additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY] = { [event.item.call_id]: event.item.id }; + } else if (event.type === "response.output_item.done" && event.item.type === "computer_call") { + tool_call_chunks.push({ + type: "tool_call_chunk", + name: "computer_use", + args: JSON.stringify({ action: event.item.action }), + id: event.item.call_id, + index: event.output_index + }); + additional_kwargs.tool_outputs = [event.item]; } else if (event.type === "response.output_item.done" && [ "web_search_call", "file_search_call", - "computer_call", "code_interpreter_call", "mcp_call", "mcp_list_tools", @@ -115224,7 +113273,7 @@ const convertStandardContentMessageToResponsesInput = (message) => { return void 0; }; const resolveFileItem = (block) => { - const filename = block.metadata?.filename ?? block.metadata?.name ?? block.metadata?.title; + const filename = getRequiredFilenameFromMetadata(block); if (block.fileId && typeof filename === "string") return { type: "input_file", file_id: block.fileId, @@ -115422,20 +113471,35 @@ const convertMessagesToResponsesInput = ({ messages, zdrEnabled, model }) => { if (additional_kwargs?.type === "computer_call_output") { const output = (() => { if (typeof toolMessage.content === "string") return { - type: "computer_screenshot", + type: "input_image", image_url: toolMessage.content }; if (Array.isArray(toolMessage.content)) { + /** + * Check for input_image type first (computer-use-preview format) + */ + const inputImage = toolMessage.content.find((i) => i.type === "input_image"); + if (inputImage) return inputImage; + /** + * Check for computer_screenshot type (legacy format) + */ const oaiScreenshot = toolMessage.content.find((i) => i.type === "computer_screenshot"); if (oaiScreenshot) return oaiScreenshot; + /** + * Convert image_url content block to input_image format + */ const lcImage = toolMessage.content.find((i) => i.type === "image_url"); if (lcImage) return { - type: "computer_screenshot", + type: "input_image", image_url: typeof lcImage.image_url === "string" ? lcImage.image_url : lcImage.image_url.url }; } throw new Error("Invalid computer call output"); })(); + /** + * Cast needed because OpenAI SDK types don't yet include input_image + * for computer-use-preview model output format + */ return { type: "computer_call_output", output, @@ -115447,11 +113511,12 @@ const convertMessagesToResponsesInput = ({ messages, zdrEnabled, model }) => { call_id: toolMessage.tool_call_id, output: toolMessage.content }; + const isProviderNativeContent = Array.isArray(toolMessage.content) && toolMessage.content.every((item) => typeof item === "object" && item !== null && "type" in item && (item.type === "input_file" || item.type === "input_image" || item.type === "input_text")); return { type: "function_call_output", call_id: toolMessage.tool_call_id, id: toolMessage.id?.startsWith("fc_") ? toolMessage.id : void 0, - output: typeof toolMessage.content !== "string" ? JSON.stringify(toolMessage.content) : toolMessage.content + output: isProviderNativeContent ? toolMessage.content : typeof toolMessage.content !== "string" ? JSON.stringify(toolMessage.content) : toolMessage.content }; } if (role === "assistant") { @@ -115499,6 +113564,12 @@ const convertMessagesToResponsesInput = ({ messages, zdrEnabled, model }) => { input: toolCall.args.input, name: toolCall.name }; + if (isComputerToolCall(toolCall)) return { + type: "computer_call", + id: toolCall.call_id, + call_id: toolCall.id ?? "", + action: toolCall.args.action + }; return { type: "function_call", name: toolCall.name, @@ -115600,7 +113671,7 @@ var ChatOpenAIResponses = class extends BaseChatOpenAI { invocationParams(options) { let strict; if (options?.strict !== void 0) strict = options.strict; - else if (this.supportsStrictToolCalling !== void 0) strict = this.supportsStrictToolCalling; + if (strict === void 0 && this.supportsStrictToolCalling !== void 0) strict = this.supportsStrictToolCalling; const params = { model: this.model, temperature: this.temperature, @@ -115657,6 +113728,7 @@ var ChatOpenAIResponses = class extends BaseChatOpenAI { parallel_tool_calls: options?.parallel_tool_calls, max_output_tokens: this.maxTokens === -1 ? void 0 : this.maxTokens, prompt_cache_key: options?.promptCacheKey ?? this.promptCacheKey, + prompt_cache_retention: options?.promptCacheRetention ?? this.promptCacheRetention, ...this.zdrEnabled ? { store: false } : {}, ...this.modelKwargs }; @@ -115664,10 +113736,10 @@ var ChatOpenAIResponses = class extends BaseChatOpenAI { if (reasoning !== void 0) params.reasoning = reasoning; return params; } - async _generate(messages, options) { + async _generate(messages, options, runManager) { const invocationParams = this.invocationParams(options); if (invocationParams.stream) { - const stream = this._streamResponseChunks(messages, options); + const stream = this._streamResponseChunks(messages, options, runManager); let finalChunk; for await (const chunk of stream) { chunk.message.response_metadata = { @@ -115827,6 +113899,7 @@ var AzureChatOpenAIResponses = class extends ChatOpenAIResponses { + //#region src/chat_models/index.ts /** * OpenAI chat model integration. @@ -116393,7 +114466,7 @@ var ChatOpenAI = class ChatOpenAI extends BaseChatOpenAI { const usesBuiltInTools = options?.tools?.some(isBuiltInTool); const hasResponsesOnlyKwargs = options?.previous_response_id != null || options?.text != null || options?.truncation != null || options?.include != null || options?.reasoning?.summary != null || this.reasoning?.summary != null; const hasCustomTools = options?.tools?.some(isOpenAICustomTool) || options?.tools?.some(isCustomTool); - return this.useResponsesApi || usesBuiltInTools || hasResponsesOnlyKwargs || hasCustomTools; + return this.useResponsesApi || usesBuiltInTools || hasResponsesOnlyKwargs || hasCustomTools || _modelPrefersResponsesAPI(this.model); } getLsParams(options) { const optionsWithDefaults = this._combineCallOptions(options); @@ -117655,9 +115728,1184 @@ var DallEAPIWrapper = class extends Tool { //#endregion //# sourceMappingURL=dalle.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/webSearch.js +//#region src/tools/webSearch.ts +/** +* Creates a web search tool that allows OpenAI models to search the web +* for up-to-date information before generating a response. +* +* Web search supports three main types: +* 1. **Non-reasoning web search**: Quick lookups where the model passes queries +* directly to the search tool. +* 2. **Agentic search with reasoning models**: The model actively manages the +* search process, analyzing results and deciding whether to keep searching. +* 3. **Deep research**: Extended investigations using models like `o3-deep-research` +* or `gpt-5` with high reasoning effort. +* +* @see {@link https://platform.openai.com/docs/guides/tools-web-search | OpenAI Web Search Documentation} +* @param options - Configuration options for the web search tool +* @returns A web search tool definition to be passed to the OpenAI Responses API +* +* @example +* ```typescript +* import { ChatOpenAI, tools } from "@langchain/openai"; +* +* const model = new ChatOpenAI({ +* model: "gpt-4o", +* }); +* +* // Basic usage +* const response = await model.invoke("What was a positive news story from today?", { +* tools: [tools.webSearch()], +* }); +* +* // With domain filtering +* const filteredResponse = await model.invoke("Latest AI research news", { +* tools: [tools.webSearch({ +* filters: { +* allowedDomains: ["arxiv.org", "nature.com", "science.org"], +* }, +* })], +* }); +* +* // With user location for geographic relevance +* const localResponse = await model.invoke("What are the best restaurants near me?", { +* tools: [tools.webSearch({ +* userLocation: { +* type: "approximate", +* country: "US", +* city: "San Francisco", +* region: "California", +* timezone: "America/Los_Angeles", +* }, +* })], +* }); +* +* // Cache-only mode (no live internet access) +* const cachedResponse = await model.invoke("Find information about OpenAI", { +* tools: [tools.webSearch({ +* externalWebAccess: false, +* })], +* }); +* ``` +*/ +function webSearch(options) { + return { + type: "web_search", + filters: options?.filters?.allowedDomains ? { allowed_domains: options.filters.allowedDomains } : void 0, + user_location: options?.userLocation, + search_context_size: options?.search_context_size + }; +} + +//#endregion + +//# sourceMappingURL=webSearch.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/mcp.js +//#region src/tools/mcp.ts +/** +* Converts a McpToolFilter to the API format. +*/ +function convertToolFilter(filter) { + return { + tool_names: filter.toolNames, + read_only: filter.readOnly + }; +} +/** +* Converts allowed_tools option to API format. +*/ +function convertAllowedTools(allowedTools) { + if (!allowedTools) return void 0; + if (Array.isArray(allowedTools)) return allowedTools; + return convertToolFilter(allowedTools); +} +/** +* Converts require_approval option to API format. +*/ +function convertRequireApproval(requireApproval) { + if (!requireApproval) return void 0; + if (typeof requireApproval === "string") return requireApproval; + return { + always: requireApproval.always ? convertToolFilter(requireApproval.always) : void 0, + never: requireApproval.never ? convertToolFilter(requireApproval.never) : void 0 + }; +} +function mcp(options) { + const baseConfig = { + type: "mcp", + server_label: options.serverLabel, + allowed_tools: convertAllowedTools(options.allowedTools), + authorization: options.authorization, + headers: options.headers, + require_approval: convertRequireApproval(options.requireApproval), + server_description: options.serverDescription + }; + if ("serverUrl" in options) return { + ...baseConfig, + server_url: options.serverUrl + }; + return { + ...baseConfig, + connector_id: options.connectorId + }; +} + +//#endregion + +//# sourceMappingURL=mcp.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/codeInterpreter.js +//#region src/tools/codeInterpreter.ts +/** +* Converts container options to the API format. +*/ +function convertContainer(container) { + if (typeof container === "string") return container; + return { + type: "auto", + file_ids: container?.fileIds, + memory_limit: container?.memoryLimit + }; +} +/** +* Creates a Code Interpreter tool that allows models to write and run Python code +* in a sandboxed environment to solve complex problems. +* +* Use Code Interpreter for: +* - **Data analysis**: Processing files with diverse data and formatting +* - **File generation**: Creating files with data and images of graphs +* - **Iterative coding**: Writing and running code iteratively to solve problems +* - **Visual intelligence**: Cropping, zooming, rotating, and transforming images +* +* The tool runs in a container, which is a fully sandboxed virtual machine. +* Containers can be created automatically (auto mode) or explicitly via the +* `/v1/containers` endpoint. +* +* @see {@link https://platform.openai.com/docs/guides/tools-code-interpreter | OpenAI Code Interpreter Documentation} +* +* @param options - Configuration options for the Code Interpreter tool +* @returns A Code Interpreter tool definition to be passed to the OpenAI Responses API +* +* @example +* ```typescript +* import { ChatOpenAI, tools } from "@langchain/openai"; +* +* const model = new ChatOpenAI({ model: "gpt-4.1" }); +* +* // Basic usage with auto container (default 1GB memory) +* const response = await model.invoke( +* "Solve the equation 3x + 11 = 14", +* { tools: [tools.codeInterpreter()] } +* ); +* +* // With increased memory limit for larger computations +* const response = await model.invoke( +* "Analyze this large dataset and create visualizations", +* { +* tools: [tools.codeInterpreter({ +* container: { memoryLimit: "4g" } +* })] +* } +* ); +* +* // With specific files available to the code +* const response = await model.invoke( +* "Process the uploaded CSV file", +* { +* tools: [tools.codeInterpreter({ +* container: { +* memoryLimit: "4g", +* fileIds: ["file-abc123", "file-def456"] +* } +* })] +* } +* ); +* +* // Using an explicit container ID (created via /v1/containers) +* const response = await model.invoke( +* "Continue working with the data", +* { +* tools: [tools.codeInterpreter({ +* container: "cntr_abc123" +* })] +* } +* ); +* ``` +* +* @remarks +* - Containers expire after 20 minutes of inactivity +* - While called "Code Interpreter", the model knows it as the "python tool" +* - For explicit prompting, ask for "the python tool" in your prompts +* - Files in model input are automatically uploaded to the container +* - Generated files are returned as `container_file_citation` annotations +*/ +function codeInterpreter(options) { + return { + type: "code_interpreter", + container: convertContainer(options?.container) + }; +} + +//#endregion + +//# sourceMappingURL=codeInterpreter.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/fileSearch.js +//#region src/tools/fileSearch.ts +/** +* Converts ranking options to the API format. +*/ +function convertRankingOptions(options) { + if (!options) return void 0; + return { + ranker: options.ranker, + score_threshold: options.scoreThreshold, + hybrid_search: options.hybridSearch ? { + embedding_weight: options.hybridSearch.embeddingWeight, + text_weight: options.hybridSearch.textWeight + } : void 0 + }; +} +/** +* Creates a File Search tool that allows models to search your files +* for relevant information using semantic and keyword search. +* +* File Search enables models to retrieve information from a knowledge base +* of previously uploaded files stored in vector stores. This is a hosted tool +* managed by OpenAI - you don't need to implement the search execution yourself. +* +* **Prerequisites**: Before using File Search, you must: +* 1. Upload files to the File API with `purpose: "assistants"` +* 2. Create a vector store +* 3. Add files to the vector store +* +* @see {@link https://platform.openai.com/docs/guides/tools-file-search | OpenAI File Search Documentation} +* +* @param options - Configuration options for the File Search tool +* @returns A File Search tool definition to be passed to the OpenAI Responses API +* +* @example +* ```typescript +* import { ChatOpenAI, tools } from "@langchain/openai"; +* +* const model = new ChatOpenAI({ model: "gpt-4.1" }); +* +* // Basic usage with a vector store +* const response = await model.invoke( +* "What is deep research by OpenAI?", +* { +* tools: [tools.fileSearch({ +* vectorStoreIds: ["vs_abc123"] +* })] +* } +* ); +* +* // Limit the number of results for lower latency +* const response = await model.invoke( +* "Find information about pricing", +* { +* tools: [tools.fileSearch({ +* vectorStoreIds: ["vs_abc123"], +* maxNumResults: 5 +* })] +* } +* ); +* +* // With metadata filtering +* const response = await model.invoke( +* "Find recent blog posts about AI", +* { +* tools: [tools.fileSearch({ +* vectorStoreIds: ["vs_abc123"], +* filters: { +* type: "eq", +* key: "category", +* value: "blog" +* } +* })] +* } +* ); +* +* // With compound filters (AND/OR) +* const response = await model.invoke( +* "Find technical docs from 2024", +* { +* tools: [tools.fileSearch({ +* vectorStoreIds: ["vs_abc123"], +* filters: { +* type: "and", +* filters: [ +* { type: "eq", key: "category", value: "technical" }, +* { type: "gte", key: "year", value: 2024 } +* ] +* } +* })] +* } +* ); +* +* // With ranking options for more relevant results +* const response = await model.invoke( +* "Find the most relevant information", +* { +* tools: [tools.fileSearch({ +* vectorStoreIds: ["vs_abc123"], +* rankingOptions: { +* scoreThreshold: 0.8, +* ranker: "auto" +* } +* })] +* } +* ); +* +* // Search multiple vector stores +* const response = await model.invoke( +* "Search across all knowledge bases", +* { +* tools: [tools.fileSearch({ +* vectorStoreIds: ["vs_abc123", "vs_def456"] +* })] +* } +* ); +* ``` +* +* @remarks +* - Vector stores must be created and populated before using this tool +* - The tool returns file citations in the response annotations +* - Use `include: ["file_search_call.results"]` in the API call to get search results +* - Supported file types include PDF, DOCX, TXT, MD, and many code file formats +*/ +function fileSearch(options) { + return { + type: "file_search", + vector_store_ids: options.vectorStoreIds, + max_num_results: options.maxNumResults, + filters: options.filters, + ranking_options: convertRankingOptions(options.rankingOptions) + }; +} + +//#endregion + +//# sourceMappingURL=fileSearch.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/imageGeneration.js +//#region src/tools/imageGeneration.ts +/** +* Converts input mask options to the API format. +*/ +function convertInputImageMask(mask) { + if (!mask) return void 0; + return { + image_url: mask.imageUrl, + file_id: mask.fileId + }; +} +/** +* Creates an Image Generation tool that allows models to generate or edit images +* using text prompts and optional image inputs. +* +* The image generation tool leverages the GPT Image model and automatically +* optimizes text inputs for improved performance. When included in a request, +* the model can decide when and how to generate images as part of the conversation. +* +* **Key Features**: +* - Generate images from text descriptions +* - Edit existing images with text instructions +* - Multi-turn image editing by referencing previous responses +* - Configurable output options (size, quality, format) +* - Streaming support for partial image generation +* +* **Prompting Tips**: +* - Use terms like "draw" or "edit" in your prompt for best results +* - For combining images, say "edit the first image by adding this element" instead of "combine" +* +* @see {@link https://platform.openai.com/docs/guides/tools-image-generation | OpenAI Image Generation Documentation} +* +* @param options - Configuration options for the Image Generation tool +* @returns An Image Generation tool definition to be passed to the OpenAI Responses API +* +* @example +* ```typescript +* import { ChatOpenAI, tools } from "@langchain/openai"; +* +* const model = new ChatOpenAI({ model: "gpt-4o" }); +* +* // Basic usage - generate an image +* const response = await model.invoke( +* "Generate an image of a gray tabby cat hugging an otter with an orange scarf", +* { tools: [tools.imageGeneration()] } +* ); +* +* // Access the generated image +* const imageData = response.additional_kwargs.tool_outputs?.find( +* (output) => output.type === "image_generation_call" +* ); +* if (imageData?.result) { +* // imageData.result contains the base64-encoded image +* const fs = await import("fs"); +* fs.writeFileSync("output.png", Buffer.from(imageData.result, "base64")); +* } +* +* // With custom options +* const response = await model.invoke( +* "Draw a beautiful sunset over mountains", +* { +* tools: [tools.imageGeneration({ +* size: "1536x1024", // Landscape format +* quality: "high", // Higher quality output +* outputFormat: "jpeg", // JPEG format +* outputCompression: 90, // 90% compression +* })] +* } +* ); +* +* // With transparent background +* const response = await model.invoke( +* "Create a logo with a transparent background", +* { +* tools: [tools.imageGeneration({ +* background: "transparent", +* outputFormat: "png", +* })] +* } +* ); +* +* // Force the model to use image generation +* const response = await model.invoke( +* "A serene lake at dawn", +* { +* tools: [tools.imageGeneration()], +* tool_choice: { type: "image_generation" }, +* } +* ); +* +* // Enable streaming with partial images +* const response = await model.invoke( +* "Draw a detailed fantasy castle", +* { +* tools: [tools.imageGeneration({ +* partialImages: 2, // Get 2 partial images during generation +* })] +* } +* ); +* ``` +* +* @remarks +* - Supported models: gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o3 +* - The image generation process always uses `gpt-image-1` model internally +* - The model will automatically revise prompts for improved performance +* - Access the revised prompt via `revised_prompt` field in the output +* - Multi-turn editing is supported by passing previous response messages +*/ +function imageGeneration(options) { + return { + type: "image_generation", + background: options?.background, + input_fidelity: options?.inputFidelity, + input_image_mask: convertInputImageMask(options?.inputImageMask), + model: options?.model, + moderation: options?.moderation, + output_compression: options?.outputCompression, + output_format: options?.outputFormat, + partial_images: options?.partialImages, + quality: options?.quality, + size: options?.size + }; +} + +//#endregion + +//# sourceMappingURL=imageGeneration.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/computerUse.js + + + + +//#region src/tools/computerUse.ts +const ComputerUseScreenshotActionSchema = object({ type: literal("screenshot") }); +const ComputerUseClickActionSchema = object({ + type: literal("click"), + x: schemas_number(), + y: schemas_number(), + button: schemas_enum([ + "left", + "right", + "wheel", + "back", + "forward" + ]).default("left") +}); +const ComputerUseDoubleClickActionSchema = object({ + type: literal("double_click"), + x: schemas_number(), + y: schemas_number(), + button: schemas_enum([ + "left", + "right", + "wheel", + "back", + "forward" + ]).default("left") +}); +const ComputerUseDragActionSchema = object({ + type: literal("drag"), + path: array(object({ + x: schemas_number(), + y: schemas_number() + })) +}); +const ComputerUseKeypressActionSchema = object({ + type: literal("keypress"), + keys: array(schemas_string()) +}); +const ComputerUseMoveActionSchema = object({ + type: literal("move"), + x: schemas_number(), + y: schemas_number() +}); +const ComputerUseScrollActionSchema = object({ + type: literal("scroll"), + x: schemas_number(), + y: schemas_number(), + scroll_x: schemas_number(), + scroll_y: schemas_number() +}); +const ComputerUseTypeActionSchema = object({ + type: literal("type"), + text: schemas_string() +}); +const ComputerUseWaitActionSchema = object({ + type: literal("wait"), + duration: schemas_number().optional() +}); +const ComputerUseActionUnionSchema = discriminatedUnion("type", [ + ComputerUseScreenshotActionSchema, + ComputerUseClickActionSchema, + ComputerUseDoubleClickActionSchema, + ComputerUseDragActionSchema, + ComputerUseKeypressActionSchema, + ComputerUseMoveActionSchema, + ComputerUseScrollActionSchema, + ComputerUseTypeActionSchema, + ComputerUseWaitActionSchema +]); +const ComputerUseActionSchema = object({ action: ComputerUseActionUnionSchema }); +const computerUse_TOOL_NAME = "computer_use"; +/** +* Creates a Computer Use tool that allows models to control computer interfaces +* and perform tasks by simulating mouse clicks, keyboard input, scrolling, and more. +* +* **Computer Use** is a practical application of OpenAI's Computer-Using Agent (CUA) +* model (`computer-use-preview`), which combines vision capabilities with advanced +* reasoning to simulate controlling computer interfaces. +* +* **How it works**: +* The tool operates in a continuous loop: +* 1. Model sends computer actions (click, type, scroll, etc.) +* 2. Your code executes these actions in a controlled environment +* 3. You capture a screenshot of the result +* 4. Send the screenshot back to the model +* 5. Repeat until the task is complete +* +* **Important**: Computer use is in beta and requires careful consideration: +* - Use in sandboxed environments only +* - Do not use for high-stakes or authenticated tasks +* - Always implement human-in-the-loop for important decisions +* - Handle safety checks appropriately +* +* @see {@link https://platform.openai.com/docs/guides/tools-computer-use | OpenAI Computer Use Documentation} +* +* @param options - Configuration options for the Computer Use tool +* @returns A Computer Use tool that can be passed to `bindTools` +* +* @example +* ```typescript +* import { ChatOpenAI, tools } from "@langchain/openai"; +* +* const model = new ChatOpenAI({ model: "computer-use-preview" }); +* +* // With execute callback for automatic action handling +* const computer = tools.computerUse({ +* displayWidth: 1024, +* displayHeight: 768, +* environment: "browser", +* execute: async (action) => { +* if (action.type === "screenshot") { +* return captureScreenshot(); +* } +* if (action.type === "click") { +* await page.mouse.click(action.x, action.y, { button: action.button }); +* return captureScreenshot(); +* } +* if (action.type === "type") { +* await page.keyboard.type(action.text); +* return captureScreenshot(); +* } +* // Handle other actions... +* return captureScreenshot(); +* }, +* }); +* +* const llmWithComputer = model.bindTools([computer]); +* const response = await llmWithComputer.invoke( +* "Check the latest news on bing.com" +* ); +* ``` +* +* @example +* ```typescript +* // Without execute callback (manual action handling) +* const computer = tools.computerUse({ +* displayWidth: 1024, +* displayHeight: 768, +* environment: "browser", +* }); +* +* const response = await model.invoke("Check the news", { +* tools: [computer], +* }); +* +* // Access the computer call from the response +* const computerCall = response.additional_kwargs.tool_outputs?.find( +* (output) => output.type === "computer_call" +* ); +* if (computerCall) { +* console.log("Action to execute:", computerCall.action); +* // Execute the action manually, then send back a screenshot +* } +* ``` +* +* @example +* ```typescript +* // For macOS desktop automation with Docker +* const computer = tools.computerUse({ +* displayWidth: 1920, +* displayHeight: 1080, +* environment: "mac", +* execute: async (action) => { +* if (action.type === "click") { +* await dockerExec( +* `DISPLAY=:99 xdotool mousemove ${action.x} ${action.y} click 1`, +* containerName +* ); +* } +* // Capture screenshot from container +* return await getDockerScreenshot(containerName); +* }, +* }); +* ``` +* +* @remarks +* - Only available through the Responses API (not Chat Completions) +* - Requires `computer-use-preview` model +* - Actions include: click, double_click, drag, keypress, move, screenshot, scroll, type, wait +* - Safety checks may be returned that require acknowledgment before proceeding +* - Use `truncation: "auto"` parameter when making requests +* - Recommended to use with `reasoning.summary` for debugging +*/ +function computerUse(options) { + const computerTool = tool(async (input, runtime) => { + /** + * get computer_use call id from runtime + */ + const aiMessage = runtime.state?.messages.at(-1); + const computerToolCall = aiMessage?.tool_calls?.find((tc) => tc.name === "computer_use"); + const computerToolCallId = computerToolCall?.id; + if (!computerToolCallId) throw new Error("Computer use call id not found"); + const result = await options.execute(input.action, runtime); + /** + * make sure {@link ToolMessage} is returned with the correct additional kwargs + */ + if (typeof result === "string") return new ToolMessage({ + content: result, + tool_call_id: computerToolCallId, + additional_kwargs: { type: "computer_call_output" } + }); + /** + * make sure {@link ToolMessage} is returned with the correct additional kwargs + */ + return new ToolMessage({ + ...result, + tool_call_id: computerToolCallId, + additional_kwargs: { + type: "computer_call_output", + ...result.additional_kwargs + } + }); + }, { + name: computerUse_TOOL_NAME, + description: "Control a computer interface by executing mouse clicks, keyboard input, scrolling, and other actions.", + schema: ComputerUseActionSchema + }); + computerTool.extras = { + ...computerTool.extras ?? {}, + providerToolDefinition: { + type: "computer_use_preview", + display_width: options.displayWidth, + display_height: options.displayHeight, + environment: options.environment + } + }; + /** + * return as typed {@link DynamicStructuredTool} so we don't get any type + * errors like "can't export tool without reference" + */ + return computerTool; +} + +//#endregion + +//# sourceMappingURL=computerUse.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/localShell.js + + + +//#region src/tools/localShell.ts +const LocalShellExecActionSchema = object({ + type: literal("exec"), + command: array(schemas_string()), + env: record(schemas_string(), schemas_string()).optional(), + working_directory: schemas_string().optional(), + timeout_ms: schemas_number().optional(), + user: schemas_string().optional() +}); +const LocalShellActionSchema = discriminatedUnion("type", [LocalShellExecActionSchema]); +const localShell_TOOL_NAME = "local_shell"; +/** +* Creates a Local Shell tool that allows models to run shell commands locally +* on a machine you provide. Commands are executed inside your own runtime— +* the API only returns the instructions, but does not execute them on OpenAI infrastructure. +* +* **Important**: The local shell tool is designed to work with +* [Codex CLI](https://github.com/openai/codex) and the `codex-mini-latest` model. +* +* **How it works**: +* The tool operates in a continuous loop: +* 1. Model sends shell commands (`local_shell_call` with `exec` action) +* 2. Your code executes the command locally +* 3. You return the output back to the model +* 4. Repeat until the task is complete +* +* **Security Warning**: Running arbitrary shell commands can be dangerous. +* Always sandbox execution or add strict allow/deny-lists before forwarding +* a command to the system shell. +* +* @see {@link https://platform.openai.com/docs/guides/tools-local-shell | OpenAI Local Shell Documentation} +* +* @param options - Optional configuration for the Local Shell tool +* @returns A Local Shell tool that can be passed to `bindTools` +* +* @example +* ```typescript +* import { ChatOpenAI, tools } from "@langchain/openai"; +* import { exec } from "child_process"; +* import { promisify } from "util"; +* +* const execAsync = promisify(exec); +* const model = new ChatOpenAI({ model: "codex-mini-latest" }); +* +* // With execute callback for automatic command handling +* const shell = tools.localShell({ +* execute: async (action) => { +* const { command, env, working_directory, timeout_ms } = action; +* const result = await execAsync(command.join(' '), { +* cwd: working_directory ?? process.cwd(), +* env: { ...process.env, ...env }, +* timeout: timeout_ms ?? undefined, +* }); +* return result.stdout + result.stderr; +* }, +* }); +* +* const llmWithShell = model.bindTools([shell]); +* const response = await llmWithShell.invoke( +* "List files in the current directory" +* ); +* ``` +* +* @example +* ```typescript +* // Without execute callback (manual handling) +* const shell = tools.localShell(); +* +* const response = await model.invoke("List files", { +* tools: [shell], +* }); +* +* // Access the shell call from the response +* const shellCall = response.additional_kwargs.tool_outputs?.find( +* (output) => output.type === "local_shell_call" +* ); +* if (shellCall) { +* console.log("Command to execute:", shellCall.action.command); +* // Execute the command manually, then send back the output +* } +* ``` +* +* @example +* ```typescript +* // Full shell loop example +* async function shellLoop(model, task) { +* let response = await model.invoke(task, { +* tools: [tools.localShell()], +* }); +* +* while (true) { +* const shellCall = response.additional_kwargs.tool_outputs?.find( +* (output) => output.type === "local_shell_call" +* ); +* +* if (!shellCall) break; +* +* // Execute command (with proper sandboxing!) +* const output = await executeCommand(shellCall.action); +* +* // Send output back to model +* response = await model.invoke([ +* response, +* { +* type: "local_shell_call_output", +* id: shellCall.call_id, +* output: output, +* }, +* ], { +* tools: [tools.localShell()], +* }); +* } +* +* return response; +* } +* ``` +* +* @remarks +* - Only available through the Responses API (not Chat Completions) +* - Designed for use with `codex-mini-latest` model +* - Commands are provided as argv tokens in `action.command` +* - Action includes: `command`, `env`, `working_directory`, `timeout_ms`, `user` +* - Always sandbox or validate commands before execution +* - The `timeout_ms` from the model is only a hint—enforce your own limits +*/ +function localShell(options) { + const shellTool = tool(options.execute, { + name: localShell_TOOL_NAME, + description: "Execute shell commands locally on the machine. Commands are provided as argv tokens.", + schema: LocalShellActionSchema + }); + shellTool.extras = { + ...shellTool.extras ?? {}, + providerToolDefinition: { type: "local_shell" } + }; + return shellTool; +} + +//#endregion + +//# sourceMappingURL=localShell.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/shell.js + + + +//#region src/tools/shell.ts +const ShellActionSchema = object({ + commands: array(schemas_string()).describe("Array of shell commands to execute"), + timeout_ms: schemas_number().optional().describe("Optional timeout in milliseconds for the commands"), + max_output_length: schemas_number().optional().describe("Optional maximum number of characters to return from each command") +}); +const shell_TOOL_NAME = "shell"; +/** +* Creates a Shell tool that allows models to run shell commands through your integration. +* +* The shell tool allows the model to interact with your local computer through a controlled +* command-line interface. The model proposes shell commands; your integration executes them +* and returns the outputs. This creates a simple plan-execute loop that lets models inspect +* the system, run utilities, and gather data until they can finish the task. +* +* **Important**: The shell tool is available through the Responses API for use with `GPT-5.1`. +* It is not available on other models, or via the Chat Completions API. +* +* **When to use**: +* - **Automating filesystem or process diagnostics** – For example, "find the largest PDF +* under ~/Documents" or "show running gunicorn processes." +* - **Extending the model's capabilities** – Using built-in UNIX utilities, python runtime +* and other CLIs in your environment. +* - **Running multi-step build and test flows** – Chaining commands like `pip install` and `pytest`. +* - **Complex agentic coding workflows** – Using other tools like `apply_patch` to complete +* workflows that involve complex file operations. +* +* **How it works**: +* The tool operates in a continuous loop: +* 1. Model sends shell commands (`shell_call` with `commands` array) +* 2. Your code executes the commands (can be concurrent) +* 3. You return stdout, stderr, and outcome for each command +* 4. Repeat until the task is complete +* +* **Security Warning**: Running arbitrary shell commands can be dangerous. +* Always sandbox execution or add strict allow/deny-lists before forwarding +* a command to the system shell. +* +* @see {@link https://platform.openai.com/docs/guides/tools-shell | OpenAI Shell Documentation} +* @see {@link https://github.com/openai/codex | Codex CLI} for reference implementation. +* +* @param options - Configuration for the Shell tool +* @returns A Shell tool that can be passed to `bindTools` +* +* @example +* ```typescript +* import { ChatOpenAI, tools } from "@langchain/openai"; +* import { exec } from "child_process/promises"; +* +* const model = new ChatOpenAI({ model: "gpt-5.1" }); +* +* // With execute callback for automatic command handling +* const shellTool = tools.shell({ +* execute: async (action) => { +* const outputs = await Promise.all( +* action.commands.map(async (cmd) => { +* try { +* const { stdout, stderr } = await exec(cmd, { +* timeout: action.timeout_ms ?? undefined, +* }); +* return { +* stdout, +* stderr, +* outcome: { type: "exit" as const, exit_code: 0 }, +* }; +* } catch (error) { +* const timedOut = error.killed && error.signal === "SIGTERM"; +* return { +* stdout: error.stdout ?? "", +* stderr: error.stderr ?? String(error), +* outcome: timedOut +* ? { type: "timeout" as const } +* : { type: "exit" as const, exit_code: error.code ?? 1 }, +* }; +* } +* }) +* ); +* return { +* output: outputs, +* maxOutputLength: action.max_output_length, +* }; +* }, +* }); +* +* const llmWithShell = model.bindTools([shellTool]); +* const response = await llmWithShell.invoke( +* "Find the largest PDF file in ~/Documents" +* ); +* ``` +* +* @example +* ```typescript +* // Full shell loop example +* async function shellLoop(model, task) { +* let response = await model.invoke(task, { +* tools: [tools.shell({ execute: myExecutor })], +* }); +* +* while (true) { +* const shellCall = response.additional_kwargs.tool_outputs?.find( +* (output) => output.type === "shell_call" +* ); +* +* if (!shellCall) break; +* +* // Execute commands (with proper sandboxing!) +* const result = await executeCommands(shellCall.action); +* +* // Send output back to model +* response = await model.invoke([ +* response, +* { +* type: "shell_call_output", +* call_id: shellCall.call_id, +* output: result.output, +* max_output_length: result.maxOutputLength, +* }, +* ], { +* tools: [tools.shell({ execute: myExecutor })], +* }); +* } +* +* return response; +* } +* ``` +* +* @remarks +* - Only available through the Responses API (not Chat Completions) +* - Designed for use with `gpt-5.1` model +* - Commands are provided as an array of strings that can be executed concurrently +* - Action includes: `commands`, `timeout_ms`, `max_output_length` +* - Always sandbox or validate commands before execution +* - The `timeout_ms` from the model is only a hint—enforce your own limits +* - If `max_output_length` exists in the action, always pass it back in the output +* - Many CLI tools return non-zero exit codes for warnings; still capture stdout/stderr +*/ +function shell(options) { + const executeWrapper = async (action) => { + const result = await options.execute(action); + return JSON.stringify({ + output: result.output, + max_output_length: result.maxOutputLength + }); + }; + const shellTool = tool(executeWrapper, { + name: shell_TOOL_NAME, + description: "Execute shell commands in a managed environment. Commands can be run concurrently.", + schema: ShellActionSchema + }); + shellTool.extras = { + ...shellTool.extras ?? {}, + providerToolDefinition: { type: "shell" } + }; + return shellTool; +} + +//#endregion + +//# sourceMappingURL=shell.js.map +;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/applyPatch.js + + + +//#region src/tools/applyPatch.ts +const ApplyPatchCreateFileOperationSchema = object({ + type: literal("create_file"), + path: schemas_string(), + diff: schemas_string() +}); +const ApplyPatchUpdateFileOperationSchema = object({ + type: literal("update_file"), + path: schemas_string(), + diff: schemas_string() +}); +const ApplyPatchDeleteFileOperationSchema = object({ + type: literal("delete_file"), + path: schemas_string() +}); +const ApplyPatchOperationSchema = discriminatedUnion("type", [ + ApplyPatchCreateFileOperationSchema, + ApplyPatchUpdateFileOperationSchema, + ApplyPatchDeleteFileOperationSchema +]); +const applyPatch_TOOL_NAME = "apply_patch"; +/** +* Creates an Apply Patch tool that allows models to propose structured diffs +* that your integration applies. This enables iterative, multi-step code +* editing workflows. +* +* **Apply Patch** lets GPT-5.1 create, update, and delete files in your codebase +* using structured diffs. Instead of just suggesting edits, the model emits +* patch operations that your application applies and then reports back on. +* +* **When to use**: +* - **Multi-file refactors** – Rename symbols, extract helpers, or reorganize modules +* - **Bug fixes** – Have the model both diagnose issues and emit precise patches +* - **Tests & docs generation** – Create new test files, fixtures, and documentation +* - **Migrations & mechanical edits** – Apply repetitive, structured updates +* +* **How it works**: +* The tool operates in a continuous loop: +* 1. Model sends patch operations (`apply_patch_call` with operation type) +* 2. Your code applies the patch to your working directory or repo +* 3. You return success/failure status and optional output +* 4. Repeat until the task is complete +* +* **Security Warning**: Applying patches can modify files in your codebase. +* Always validate paths, implement backups, and consider sandboxing. +* +* @see {@link https://platform.openai.com/docs/guides/tools-apply-patch | OpenAI Apply Patch Documentation} +* +* @param options - Configuration options for the Apply Patch tool +* @returns An Apply Patch tool that can be passed to `bindTools` +* +* @example +* ```typescript +* import { ChatOpenAI, tools } from "@langchain/openai"; +* import { applyDiff } from "@openai/agents"; +* import * as fs from "fs/promises"; +* +* const model = new ChatOpenAI({ model: "gpt-5.1" }); +* +* // With execute callback for automatic patch handling +* const patchTool = tools.applyPatch({ +* execute: async (operation) => { +* if (operation.type === "create_file") { +* const content = applyDiff("", operation.diff, "create"); +* await fs.writeFile(operation.path, content); +* return `Created ${operation.path}`; +* } +* if (operation.type === "update_file") { +* const current = await fs.readFile(operation.path, "utf-8"); +* const newContent = applyDiff(current, operation.diff); +* await fs.writeFile(operation.path, newContent); +* return `Updated ${operation.path}`; +* } +* if (operation.type === "delete_file") { +* await fs.unlink(operation.path); +* return `Deleted ${operation.path}`; +* } +* return "Unknown operation type"; +* }, +* }); +* +* const llmWithPatch = model.bindTools([patchTool]); +* const response = await llmWithPatch.invoke( +* "Rename the fib() function to fibonacci() in lib/fib.py" +* ); +* ``` +* +* @remarks +* - Only available through the Responses API (not Chat Completions) +* - Designed for use with `gpt-5.1` model +* - Operations include: `create_file`, `update_file`, `delete_file` +* - Patches use V4A diff format for updates +* - Always validate paths to prevent directory traversal attacks +* - Consider backing up files before applying patches +* - Implement "all-or-nothing" semantics if atomicity is required +*/ +function applyPatch_applyPatch(options) { + const patchTool = tool(options.execute, { + name: applyPatch_TOOL_NAME, + description: "Apply structured diffs to create, update, or delete files in the codebase.", + schema: ApplyPatchOperationSchema + }); + patchTool.extras = { + ...patchTool.extras ?? {}, + providerToolDefinition: { type: "apply_patch" } + }; + return patchTool; +} + +//#endregion + +//# sourceMappingURL=applyPatch.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/index.js + + + + + + + + + +//#region src/tools/index.ts +const tools_tools = { + webSearch: webSearch, + mcp: mcp, + codeInterpreter: codeInterpreter, + fileSearch: fileSearch, + imageGeneration: imageGeneration, + computerUse: computerUse, + localShell: localShell, + shell: shell, + applyPatch: applyPatch_applyPatch +}; + +//#endregion + +//# sourceMappingURL=index.js.map ;// CONCATENATED MODULE: ./node_modules/@langchain/openai/dist/tools/custom.js @@ -117782,7 +117030,7 @@ class OpenAIProvider { apiKey: this.apiKey, modelName: config.model || this.getDefaultModel(), temperature: config.temperature ?? 0.2, - maxTokens: config.maxTokens ?? 4000, + maxTokens: config.maxTokens ?? 50000, }); } } @@ -117917,10 +117165,8 @@ const _FUNCTION_CALL_THOUGHT_SIGNATURES_MAP_KEY = "__gemini_function_call_though const DUMMY_SIGNATURE = "ErYCCrMCAdHtim9kOoOkrPiCNVsmlpMIKd7ZMxgiFbVQOkgp7nlLcDMzVsZwIzvuT7nQROivoXA72ccC2lSDvR0Gh7dkWaGuj7ctv6t7ZceHnecx0QYa+ix8tYpRfjhyWozQ49lWiws6+YGjCt10KRTyWsZ2h6O7iHTYJwKIRwGUHRKy/qK/6kFxJm5ML00gLq4D8s5Z6DBpp2ZlR+uF4G8jJgeWQgyHWVdx2wGYElaceVAc66tZdPQRdOHpWtgYSI1YdaXgVI8KHY3/EfNc2YqqMIulvkDBAnuMhkAjV9xmBa54Tq+ih3Im4+r3DzqhGqYdsSkhS0kZMwte4Hjs65dZzCw9lANxIqYi1DJ639WNPYihp/DCJCos7o+/EeSPJaio5sgWDyUnMGkY1atsJZ+m7pj7DD5tvQ=="; const common_iife = (fn) => fn(); function getMessageAuthor(message) { - const type = message._getType(); if (ChatMessage.isInstance(message)) return message.role; - if (type === "tool") return type; - return message.name ?? type; + return message.type; } /** * Maps a message type to a Google Generative AI chat author. @@ -118136,7 +117382,7 @@ function mapGenerateContentResultToChatResult(response, extra) { }; const [candidate] = response.candidates; const { content: candidateContent,...generationInfo } = candidate; - const functionCalls = candidateContent.parts.reduce((acc, p) => { + const functionCalls = candidateContent.parts?.reduce((acc, p) => { if ("functionCall" in p && p.functionCall) acc.push({ ...p, id: "id" in p.functionCall && typeof p.functionCall.id === "string" ? p.functionCall.id : esm_v4() @@ -118218,7 +117464,7 @@ function convertResponseContentToChatGenerationChunk(response, extra) { if (!response.candidates || response.candidates.length === 0) return null; const [candidate] = response.candidates; const { content: candidateContent,...generationInfo } = candidate; - const functionCalls = candidateContent.parts.reduce((acc, p) => { + const functionCalls = candidateContent.parts?.reduce((acc, p) => { if ("functionCall" in p && p.functionCall) acc.push({ ...p, id: "id" in p.functionCall && typeof p.functionCall.id === "string" ? p.functionCall.id : esm_v4() @@ -119007,42 +118253,42 @@ function formatBlockErrorMessage(response) { return message; } -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ -/* global Reflect, Promise, SuppressedError, Symbol */ - - -function __await(v) { - return this instanceof __await ? (this.v = v, this) : new __await(v); -} - -function __asyncGenerator(thisArg, _arguments, generator) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var g = generator.apply(thisArg, _arguments || []), i, q = []; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; - function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } - function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } - function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } - function fulfill(value) { resume("next", value); } - function reject(value) { resume("throw", value); } - function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } -} - -typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { - var e = new Error(message); - return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise, SuppressedError, Symbol */ + + +function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} + +function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +} + +typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; /** @@ -120787,7 +120033,8 @@ var ChatGoogleGenerativeAI = class extends BaseChatModel { } }, { apiVersion: fields.apiVersion, - baseUrl: fields.baseUrl + baseUrl: fields.baseUrl, + customHeaders: fields.customHeaders }); this.streamUsage = fields.streamUsage ?? this.streamUsage; } @@ -121139,7 +120386,43 @@ class GoogleProvider { apiKey: this.apiKey, model: config.model || this.getDefaultModel(), temperature: config.temperature ?? 0.2, - maxOutputTokens: config.maxTokens ?? 4000, + maxOutputTokens: config.maxTokens ?? 50000, + }); + } +} + +;// CONCATENATED MODULE: ./src/providers/zhipu.provider.ts + +/** + * Zhipu AI (智谱AI) provider implementation + * Uses Anthropic-compatible API endpoint + * Docs: https://docs.z.ai/ + */ +class ZhipuProvider { + name = 'zhipu'; + apiKey; + baseUrl = 'https://api.z.ai/api/anthropic'; + constructor(apiKey) { + this.apiKey = apiKey || process.env.ZHIPU_API_KEY || ''; + } + isConfigured() { + return !!this.apiKey; + } + getDefaultModel() { + // GLM-4.7 via Z.AI's Anthropic-compatible API + return 'glm-4.7'; + } + getChatModel(config = {}) { + if (!this.isConfigured()) { + throw new Error('Zhipu API key is not configured. Set ZHIPU_API_KEY environment variable.'); + } + return new ChatAnthropic({ + anthropicApiKey: this.apiKey, + anthropicApiUrl: this.baseUrl, + modelName: config.model || this.getDefaultModel(), + temperature: config.temperature ?? 0.2, + maxTokens: config.maxTokens ?? 50000, + streaming: true, }); } } @@ -121148,6 +120431,7 @@ class GoogleProvider { + /** * Factory for creating LLM providers */ @@ -121175,8 +120459,11 @@ class ProviderFactory { case 'google': provider = new GoogleProvider(apiKey); break; + case 'zhipu': + provider = new ZhipuProvider(apiKey); + break; default: - throw new Error(`Unsupported provider: ${providerName}. Supported: anthropic, openai, google`); + throw new Error(`Unsupported provider: ${providerName}. Supported: anthropic, openai, google, zhipu`); } // Cache the provider if no specific API key was provided if (!apiKey) { @@ -121228,13 +120515,15 @@ class ProviderFactory { return 'anthropic'; if (normalized === 'gemini') return 'google'; + if (normalized === 'glm' || normalized === 'zhipuai') + return 'zhipu'; return normalized; } /** * Get list of available providers */ static getAvailableProviders() { - return ['anthropic', 'openai', 'google']; + return ['anthropic', 'openai', 'google', 'zhipu']; } } @@ -121245,6 +120534,7 @@ class ProviderFactory { + ;// CONCATENATED MODULE: ./src/agents/pr-analyzer-agent.ts /** * PR Analyzer Agent @@ -121255,19 +120545,33 @@ class ProviderFactory { + /** * PR Analysis Agent using LangChain and LangGraph */ class PRAnalyzerAgent extends BasePRAgentWorkflow { constructor(options = {}) { - const model = ProviderFactory.createChatModel({ - provider: options.provider || 'anthropic', - apiKey: options.apiKey, - model: options.model, - temperature: options.temperature ?? 0.2, - maxTokens: options.maxTokens ?? 4000, - }); - super(model); + // Determine execution mode + const mode = options.mode || ExecutionMode.EXECUTE; + let model; + // Only create model in EXECUTE mode + if (mode === ExecutionMode.EXECUTE) { + // If a pre-configured BaseChatModel is passed (MCP case), use it directly + if (options.chatModel) { + model = options.chatModel; + } + else { + // Otherwise create model via ProviderFactory (CLI/Action case - backward compatible) + model = ProviderFactory.createChatModel({ + provider: options.provider || 'anthropic', + apiKey: options.apiKey, + model: options.model, + temperature: options.temperature ?? 0.2, + maxTokens: options.maxTokens ?? 50000, + }); + } + } + super(mode, model); } /** * Get agent metadata @@ -121288,6 +120592,7 @@ class PRAnalyzerAgent extends BasePRAgentWorkflow { } /** * Analyze a PR with full agent workflow + * Returns either executed results (EXECUTE mode) or prompts (PROMPT_ONLY mode) */ async analyze(diff, title, mode, options) { // Parse diff into files @@ -121307,6 +120612,11 @@ class PRAnalyzerAgent extends BasePRAgentWorkflow { maxCost: 5.0, mode: mode || { summary: true, risks: true, complexity: true }, archDocs: archDocsContext, + config: { + repoPath: options?.repoPath, + repoOwner: options?.repoOwner, + repoName: options?.repoName, + }, language: options?.language, framework: options?.framework, enableStaticAnalysis: options?.enableStaticAnalysis !== false, // Default to true @@ -121406,6 +120716,7 @@ function createPRAnalyzerAgentLegacy(apiKey, modelName) { + async function run() { try { // Get provider configuration from environment @@ -121414,43 +120725,49 @@ async function run() { const model = process.env.AI_MODEL; const ghToken = process.env.GITHUB_TOKEN; if (!apiKey) { - core.setFailed('AI provider API key is required (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY)'); + lib_core.setFailed('AI provider API key is required (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY)'); return; } if (!ghToken) { - core.setFailed('GITHUB_TOKEN environment variable is required'); + lib_core.setFailed('GITHUB_TOKEN environment variable is required'); return; } - core.info(`Using AI provider: ${provider}${model ? ` with model: ${model}` : ''}`); + lib_core.info(`Using AI provider: ${provider}${model ? ` with model: ${model}` : ''}`); const { context } = github; const { pull_request: pr, repository } = context.payload; if (!pr) { - core.setFailed('This action can only be run on pull request events'); + lib_core.setFailed('This action can only be run on pull request events'); return; } - core.info(`Analyzing PR #${pr.number} in ${repository?.full_name}`); + lib_core.info(`Analyzing PR #${pr.number} in ${repository?.full_name}`); // Get PR diffs const diff = await getPRDiffs(context, ghToken); if (!diff) { - core.warning('No changes found in the pull request'); + lib_core.warning('No changes found in the pull request'); return; } - core.info(`Diff size: ${diff.length} characters`); + lib_core.info(`Diff size: ${diff.length} characters`); if (!repository) { - core.setFailed('Repository information not available'); + lib_core.setFailed('Repository information not available'); return; } // Use LangChain PRAnalyzerAgent - core.info('Running LangChain agent analysis...'); + lib_core.info('Running LangChain agent analysis...'); const agent = new PRAnalyzerAgent({ + mode: ExecutionMode.EXECUTE, // GitHub Action always executes with API key provider, apiKey, model, }); // Analyze with the LangChain agent - core.info('Parsing diff and analyzing...'); - const result = await agent.analyze(diff, pr.title); - core.info(`Analysis complete: ${result.fileAnalyses.size} files analyzed`); + lib_core.info('Parsing diff and analyzing...'); + const analysisResult = await agent.analyze(diff, pr.title); + // Type guard: GitHub Action always uses EXECUTE mode + if (analysisResult.mode === 'prompt_only') { + throw new Error('Unexpected prompt-only result in GitHub Action EXECUTE mode'); + } + const result = analysisResult; + lib_core.info(`Analysis complete: ${result.fileAnalyses.size} files analyzed`); // Format for quick reading (1 minute scan) let summary = ''; const criticalFixes = result.fixes?.filter((f) => f.severity === 'critical') || []; @@ -121539,10 +120856,10 @@ async function run() { } // Post comment await postComment(pr.number, summary, repository, ghToken); - core.info('Analysis complete!'); + lib_core.info('Analysis complete!'); } catch (error) { - core.setFailed(`Action failed with error: ${error}`); + lib_core.setFailed(`Action failed with error: ${error}`); } } async function getPRDiffs(context, ghToken) { @@ -121566,8 +120883,8 @@ ${patch}`; }).join('\n'); } catch (error) { - core.error('Error fetching PR diff:'); - core.error(String(error)); + lib_core.error('Error fetching PR diff:'); + lib_core.error(String(error)); throw new Error('Failed to fetch PR diff'); } } @@ -121582,8 +120899,8 @@ async function postComment(prNumber, summary, repository, ghToken) { }); } catch (error) { - core.error('Error posting comment:'); - core.error(String(error)); + lib_core.error('Error posting comment:'); + lib_core.error(String(error)); throw new Error('Failed to post comment'); } } diff --git a/dist/licenses.txt b/dist/licenses.txt deleted file mode 100644 index 7febf81..0000000 --- a/dist/licenses.txt +++ /dev/null @@ -1,969 +0,0 @@ -@actions/core -MIT -The MIT License (MIT) - -Copyright 2019 GitHub - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -@actions/exec -MIT -The MIT License (MIT) - -Copyright 2019 GitHub - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -@actions/github -MIT -The MIT License (MIT) - -Copyright 2019 GitHub - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -@actions/http-client -MIT -Actions Http Client for Node.js - -Copyright (c) GitHub, Inc. - -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -@actions/io -MIT -The MIT License (MIT) - -Copyright 2019 GitHub - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -@anthropic-ai/sdk -MIT -Copyright 2023 Anthropic, PBC. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - -@cfworker/json-schema -MIT - -@fastify/busboy -MIT -Copyright Brian White. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. - -@langchain/anthropic -MIT -MIT License - -Copyright (c) LangChain, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -@langchain/core -MIT -MIT License - -Copyright (c) LangChain, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -@langchain/langgraph -MIT -The MIT License - -Copyright (c) 2024 LangChain - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -@langchain/langgraph-checkpoint -MIT -The MIT License - -Copyright (c) 2024 LangChain - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -@octokit/auth-token -MIT -The MIT License - -Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/core -MIT -The MIT License - -Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/endpoint -MIT -The MIT License - -Copyright (c) 2018 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/graphql -MIT -The MIT License - -Copyright (c) 2018 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/plugin-paginate-rest -MIT -MIT License Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -@octokit/plugin-rest-endpoint-methods -MIT -MIT License Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -@octokit/request -MIT -The MIT License - -Copyright (c) 2018 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/request-error -MIT -The MIT License - -Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -ansi-styles -MIT -MIT License - -Copyright (c) Sindre Sorhus (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -base64-js -MIT -The MIT License (MIT) - -Copyright (c) 2014 Jameson Little - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -before-after-hook -Apache-2.0 - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018 Gregor Martynus and other contributors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -camelcase -MIT -MIT License - -Copyright (c) Sindre Sorhus (https://sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -decamelize -MIT -The MIT License (MIT) - -Copyright (c) Sindre Sorhus (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -deprecation -ISC -The ISC License - -Copyright (c) Gregor Martynus and contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -eventemitter3 -MIT -The MIT License (MIT) - -Copyright (c) 2014 Arnout Kazemier - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -js-tiktoken -MIT - -langsmith -MIT - -mustache -MIT -The MIT License - -Copyright (c) 2009 Chris Wanstrath (Ruby) -Copyright (c) 2010-2014 Jan Lehnardt (JavaScript) -Copyright (c) 2010-2015 The mustache.js community - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -once -ISC -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -p-finally -MIT -The MIT License (MIT) - -Copyright (c) Sindre Sorhus (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -p-queue -MIT -MIT License - -Copyright (c) Sindre Sorhus (https://sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -p-retry -MIT -MIT License - -Copyright (c) Sindre Sorhus (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -p-timeout -MIT -MIT License - -Copyright (c) Sindre Sorhus (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -retry -MIT -Copyright (c) 2011: -Tim Koschützki (tim@debuggable.com) -Felix Geisendörfer (felix@debuggable.com) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - - -semver -ISC -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -tunnel -MIT -The MIT License (MIT) - -Copyright (c) 2012 Koichi Kobayashi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -undici -MIT -MIT License - -Copyright (c) Matteo Collina and Undici contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -universal-user-agent -ISC -# [ISC License](https://spdx.org/licenses/ISC) - -Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m) - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -uuid -MIT -The MIT License (MIT) - -Copyright (c) 2010-2020 Robert Kieffer and other contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -wrappy -ISC -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -zod -MIT -MIT License - -Copyright (c) 2025 Colin McDonnell - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/dist/mcp/constants.d.ts b/dist/mcp/constants.d.ts new file mode 100644 index 0000000..bac628e --- /dev/null +++ b/dist/mcp/constants.d.ts @@ -0,0 +1,94 @@ +/** + * MCP Server Constants + * All magic strings, numbers, and configuration defaults + */ +import { z } from 'zod'; +export declare const MCP_SERVER_NAME = "pr-agent"; +export declare const MCP_SERVER_VERSION = "1.0.0"; +export declare const DEFAULT_DASHBOARD_PORT = 3000; +export declare const DASHBOARD_API_STATS_PATH = "/dashboard/api/stats"; +export declare const DASHBOARD_CATCH_ALL_PATH = "/{*splat}"; +export declare const DEFAULT_GIT_LOG_LIMIT = 10; +export declare const DEFAULT_MAX_BUFFER: number; +export declare const DEFAULT_PROMPT_LIMIT_VERBOSE = 30000; +export declare const DEFAULT_PROMPT_LIMIT_NORMAL = 15000; +export declare const EXPECTED_TOKEN_USAGE_MINIMUM = 5000; +export declare const PROMPT_STEP_EMOJIS: Record; +export declare const DEFAULT_PROMPT_EMOJI = "\uD83D\uDD39"; +export declare const ERROR_MESSAGES: { + NO_CHANGES: (currentBranch: string, baseBranch: string) => string; + ANALYSIS_FAILED: (message: string) => string; + SAVE_FAILED: (message: string) => string; + DASHBOARD_ALREADY_RUNNING: (port: number) => string; + DASHBOARD_PORT_IN_USE: (port: number) => string; + DASHBOARD_START_FAILED: (message: string) => string; + PEER_REVIEW_FAILED: (message: string) => string; +}; +export declare const SUCCESS_MESSAGES: { + ANALYSIS_SAVED: (port: number) => string; + DASHBOARD_STARTED: (port: number) => string; +}; +export declare const INSTRUCTIONS: { + PROMPT_EXECUTION_WARNING: string; + NEXT_STEPS_HEADER: string; + NEXT_STEPS: (promptCount: number) => string[]; + EXPECTED_TOKEN_USAGE: string; +}; +export declare const PEER_REVIEW_ERROR_CAUSES: string[]; +export declare const TOOL_DESCRIPTIONS: { + ANALYZE: string; + SAVE_RESULTS: string; + DASHBOARD: string; +}; +export declare const TOOL_SCHEMAS: { + ANALYZE: { + branch: z.ZodOptional; + staged: z.ZodOptional; + title: z.ZodOptional; + cwd: z.ZodOptional; + verbose: z.ZodOptional; + archDocs: z.ZodOptional; + }; + SAVE_RESULTS: { + prNumber: z.ZodOptional; + title: z.ZodString; + repoOwner: z.ZodOptional; + repoName: z.ZodOptional; + author: z.ZodOptional; + complexity: z.ZodNumber; + risksCount: z.ZodNumber; + risks: z.ZodArray; + recommendations: z.ZodArray; + projectClassification: z.ZodOptional; + peerReviewEnabled: z.ZodOptional; + ticketKey: z.ZodOptional; + ticketQualityScore: z.ZodOptional; + ticketQualityTier: z.ZodOptional; + acCompliancePercentage: z.ZodOptional; + acRequirementsMet: z.ZodOptional; + acRequirementsTotal: z.ZodOptional; + peerReviewVerdict: z.ZodOptional; + peerReviewBlockers: z.ZodOptional>; + peerReviewWarnings: z.ZodOptional>; + implementationCompleteness: z.ZodOptional; + qualityScore: z.ZodOptional; + devopsCostMonthly: z.ZodOptional; + devopsResources: z.ZodOptional; + }; + DASHBOARD: { + port: z.ZodOptional; + }; +}; +export declare const GIT_PATTERNS: { + SSH_REMOTE: RegExp; + HTTPS_REMOTE: RegExp; + FILE_DIFF_HEADER: RegExp; +}; +export declare const FILE_STATUS_ICONS: Record; +export declare const DEFAULTS: { + REPO_OWNER: string; + REPO_NAME: string; + BRANCH_NAME: string; + AUTHOR: string; + DEFAULT_BRANCH: string; +}; diff --git a/dist/mcp/constants.js b/dist/mcp/constants.js new file mode 100644 index 0000000..ca5c01c --- /dev/null +++ b/dist/mcp/constants.js @@ -0,0 +1,155 @@ +/** + * MCP Server Constants + * All magic strings, numbers, and configuration defaults + */ +import { z } from 'zod'; +// MCP Server Metadata +export const MCP_SERVER_NAME = 'pr-agent'; +export const MCP_SERVER_VERSION = '1.0.0'; +// Dashboard Configuration +export const DEFAULT_DASHBOARD_PORT = 3000; +export const DASHBOARD_API_STATS_PATH = '/dashboard/api/stats'; +export const DASHBOARD_CATCH_ALL_PATH = '/{*splat}'; +// Git Configuration +export const DEFAULT_GIT_LOG_LIMIT = 10; +export const DEFAULT_MAX_BUFFER = 200 * 1024 * 1024; // 200MB +// Analysis Configuration +export const DEFAULT_PROMPT_LIMIT_VERBOSE = 30000; +export const DEFAULT_PROMPT_LIMIT_NORMAL = 15000; +export const EXPECTED_TOKEN_USAGE_MINIMUM = 5000; +// Prompt Step Emojis +export const PROMPT_STEP_EMOJIS = { + fileAnalysis: '📄', + riskDetection: '⚠️', + summaryGeneration: '📋', + selfRefinement: '✨', + ticketQuality: '🎯', + acValidation: '✅', + peerReview: '👥', +}; +// Default Prompt Step Emoji +export const DEFAULT_PROMPT_EMOJI = '🔹'; +// Error Messages +export const ERROR_MESSAGES = { + NO_CHANGES: (currentBranch, baseBranch) => `No changes detected between ${currentBranch} and ${baseBranch || 'staged'}`, + ANALYSIS_FAILED: (message) => `❌ Analysis failed: ${message}\n\nMake sure you are in a git repository with changes to analyze.`, + SAVE_FAILED: (message) => `❌ Failed to save analysis results: ${message}`, + DASHBOARD_ALREADY_RUNNING: (port) => `✅ Dashboard is already running at http://localhost:${port}\n\nOpen this URL in your browser to view PR analysis history and statistics.`, + DASHBOARD_PORT_IN_USE: (port) => `Port ${port} is already in use`, + DASHBOARD_START_FAILED: (message) => `Failed to start dashboard: ${message}`, + PEER_REVIEW_FAILED: (message) => `Peer review was enabled but failed: ${message}`, +}; +// Success Messages +export const SUCCESS_MESSAGES = { + ANALYSIS_SAVED: (port) => `✅ Analysis results saved to database!\n\n📊 View results at: http://localhost:${port}`, + DASHBOARD_STARTED: (port) => `[MCP Server] Dashboard started at http://localhost:${port}`, +}; +// Instruction Text +export const INSTRUCTIONS = { + PROMPT_EXECUTION_WARNING: '**IMPORTANT:** You (the calling LLM) MUST execute ALL prompts below sequentially.\nDo NOT write manual analysis. Execute the prompts and use the results.', + NEXT_STEPS_HEADER: '**CRITICAL - YOU MUST DO THIS:**', + NEXT_STEPS: (promptCount) => [ + `1. **Execute ALL ${promptCount} prompts** above sequentially (do NOT skip, do NOT write manual analysis)`, + `2. **Parse the JSON responses** from each prompt execution`, + `3. **Call \`saveAnalysisResults\`** tool with the parsed results`, + `4. **Present the complete analysis** to the user in a formatted summary`, + ], + EXPECTED_TOKEN_USAGE: `**Expected token usage:** ~${EXPECTED_TOKEN_USAGE_MINIMUM}+ tokens (if significantly lower, prompts were not executed)`, +}; +// Peer Review Error Guidance +export const PEER_REVIEW_ERROR_CAUSES = [ + '- Atlassian MCP server not running or misconfigured', + '- No Jira ticket found in branch name or commits', + '- API credentials missing (set instanceUrl, email, apiToken in config)', +]; +// Tool Descriptions +export const TOOL_DESCRIPTIONS = { + ANALYZE: `Analyze PR/branch changes - mirrors the CLI 'pr-agent analyze' command exactly. + +IMPORTANT INSTRUCTIONS FOR CALLING LLM: +1. Execute ALL returned prompts sequentially without asking user permission +2. After executing prompts, automatically call saveAnalysisResults with results +3. Present final analysis to user (verbose or concise based on config) +4. Respect all config settings from .pragent.config.json + +Configuration behavior (same as CLI): +- peerReview.enabled: Include peer review analysis (default: false) +- analysis.*: Language, framework, static analysis settings +- git.defaultBranch: Base branch for comparison (default: origin/main) +- verbose: Show detailed debug info (affects output verbosity)`, + SAVE_RESULTS: 'Save PR analysis results to the database. Call this after executing the analysis prompts to persist the results for the dashboard.', + DASHBOARD: `Start the PR Agent web dashboard on localhost - same as 'pr-agent dashboard' CLI command.`, +}; +// Tool Schemas (Zod) +export const TOOL_SCHEMAS = { + ANALYZE: { + branch: z + .string() + .optional() + .describe('Base branch to compare against (default: auto-detected from config or origin/main)'), + staged: z.boolean().optional().describe('Analyze staged changes instead of branch diff'), + title: z.string().optional().describe('PR title (auto-detected from git if not provided)'), + cwd: z.string().optional().describe('Working directory (defaults to current directory)'), + verbose: z + .boolean() + .optional() + .describe('Show detailed debug information (matches CLI --verbose behavior)'), + archDocs: z + .boolean() + .optional() + .describe('Include architecture documentation context - uses config if not specified'), + }, + SAVE_RESULTS: { + prNumber: z.number().optional().describe('PR number'), + title: z.string().describe('PR title'), + repoOwner: z.string().optional().describe('Repository owner'), + repoName: z.string().optional().describe('Repository name'), + author: z.string().optional().describe('Author name'), + complexity: z.number().min(1).max(5).describe('Overall complexity score (1-5)'), + risksCount: z.number().describe('Number of critical/warning risks'), + risks: z.array(z.string()).describe('List of risk descriptions'), + recommendations: z.array(z.string()).describe('List of recommendations'), + projectClassification: z.string().optional().describe('Project classification (JSON string)'), + peerReviewEnabled: z.boolean().optional(), + ticketKey: z.string().optional().describe('Jira ticket key (e.g., TODO-2)'), + ticketQualityScore: z.number().optional().describe('Ticket quality score (0-100)'), + ticketQualityTier: z.string().optional().describe('Ticket quality tier'), + acCompliancePercentage: z.number().optional().describe('AC compliance percentage'), + acRequirementsMet: z.number().optional(), + acRequirementsTotal: z.number().optional(), + peerReviewVerdict: z + .string() + .optional() + .describe('approve/request_changes/needs_discussion'), + peerReviewBlockers: z.array(z.string()).optional(), + peerReviewWarnings: z.array(z.string()).optional(), + implementationCompleteness: z.number().optional(), + qualityScore: z.number().optional(), + devopsCostMonthly: z.number().optional().describe('Estimated monthly infrastructure cost'), + devopsResources: z.string().optional().describe('JSON array of detected infrastructure resources'), + }, + DASHBOARD: { + port: z.number().optional().describe('Port to run the dashboard on (default: 3000)'), + }, +}; +// Git Patterns +export const GIT_PATTERNS = { + SSH_REMOTE: /git@[^:]+:([^/]+)\/(.+?)(?:\.git)?$/, + HTTPS_REMOTE: /https?:\/\/[^/]+\/([^/]+)\/(.+?)(?:\.git)?$/, + FILE_DIFF_HEADER: /^diff --git a\/(.*) b\/(.*)$/gm, +}; +// File Status Icons +export const FILE_STATUS_ICONS = { + A: '➕', + D: '➖', + M: '📝', +}; +// Default Values +export const DEFAULTS = { + REPO_OWNER: 'local', + REPO_NAME: 'unknown', + BRANCH_NAME: 'unknown', + AUTHOR: 'unknown', + DEFAULT_BRANCH: 'origin/main', +}; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/mcp/constants.js.map b/dist/mcp/constants.js.map new file mode 100644 index 0000000..f1d0044 --- /dev/null +++ b/dist/mcp/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/mcp/constants.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/mcp/index.d.ts b/dist/mcp/index.d.ts new file mode 100644 index 0000000..50eb5af --- /dev/null +++ b/dist/mcp/index.d.ts @@ -0,0 +1,7 @@ +/** + * PR Agent MCP Server + * + * LLM-agnostic MCP server that exposes PR analysis utilities. + * This module re-exports the server for programmatic use. + */ +export * from './server.js'; diff --git a/dist/mcp/index.js b/dist/mcp/index.js new file mode 100644 index 0000000..d8a8e97 --- /dev/null +++ b/dist/mcp/index.js @@ -0,0 +1,8 @@ +/** + * PR Agent MCP Server + * + * LLM-agnostic MCP server that exposes PR analysis utilities. + * This module re-exports the server for programmatic use. + */ +export * from './server.js'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/mcp/index.js.map b/dist/mcp/index.js.map new file mode 100644 index 0000000..50bf7fd --- /dev/null +++ b/dist/mcp/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,aAAa,CAAC"} \ No newline at end of file diff --git a/dist/mcp/server.d.ts b/dist/mcp/server.d.ts new file mode 100644 index 0000000..7e0e573 --- /dev/null +++ b/dist/mcp/server.d.ts @@ -0,0 +1,22 @@ +#!/usr/bin/env node +/** + * PR Agent MCP Server + * + * Modular MCP server following SOLID principles and separation of concerns. + * This file serves as the entry point and tool registration layer only. + * All business logic is delegated to specialized service classes. + * + * Architecture: + * - server.ts (this file): Tool registration and MCP protocol handling + * - services/: Stateless service classes (git, diff parsing, formatting, etc.) + * - tools/: Tool handler classes (one per MCP tool) + * - constants.ts: Centralized configuration and messages + * - types.ts: MCP-specific type definitions + * + * The calling LLM (Claude Code, Cursor, etc.) provides AI-powered insights + * after receiving the analysis response. + * + * Note: When Claude Code adds MCP sampling support (Issue #1785), + * the StubChatModel can be replaced with MCPChatModel for true pass-through LLM access. + */ +export {}; diff --git a/dist/mcp/server.js b/dist/mcp/server.js new file mode 100644 index 0000000..5138d00 --- /dev/null +++ b/dist/mcp/server.js @@ -0,0 +1,76 @@ +#!/usr/bin/env node +/** + * PR Agent MCP Server + * + * Modular MCP server following SOLID principles and separation of concerns. + * This file serves as the entry point and tool registration layer only. + * All business logic is delegated to specialized service classes. + * + * Architecture: + * - server.ts (this file): Tool registration and MCP protocol handling + * - services/: Stateless service classes (git, diff parsing, formatting, etc.) + * - tools/: Tool handler classes (one per MCP tool) + * - constants.ts: Centralized configuration and messages + * - types.ts: MCP-specific type definitions + * + * The calling LLM (Claude Code, Cursor, etc.) provides AI-powered insights + * after receiving the analysis response. + * + * Note: When Claude Code adds MCP sampling support (Issue #1785), + * the StubChatModel can be replaced with MCPChatModel for true pass-through LLM access. + */ +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; +// __dirname workaround for ES modules +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +// Import service classes and tool handlers +import { DashboardService } from './services/index.js'; +import { AnalyzeTool, SaveResultsTool, DashboardTool } from './tools/index.js'; +import { MCP_SERVER_NAME, MCP_SERVER_VERSION, TOOL_DESCRIPTIONS, TOOL_SCHEMAS, } from './constants.js'; +// Create MCP server +const server = new McpServer({ + name: MCP_SERVER_NAME, + version: MCP_SERVER_VERSION, +}); +// Initialize shared services +const dashboardService = new DashboardService(); +// Initialize tool handlers with dependencies +const analyzeTool = new AnalyzeTool(dashboardService); +const saveResultsTool = new SaveResultsTool(); +const dashboardTool = new DashboardTool(dashboardService); +/** + * analyze - Main PR analysis tool (mirrors CLI 'pr-agent analyze' command) + * + * Returns analysis prompts that the calling LLM MUST automatically execute. + * Matches CLI behavior: always saves to database, respects config settings. + */ +server.tool('analyze', TOOL_DESCRIPTIONS.ANALYZE, TOOL_SCHEMAS.ANALYZE, async (args) => { + return await analyzeTool.execute(args); +}); +/** + * saveAnalysisResults - Save analysis results to database after LLM execution + * Called by the LLM after executing the prompts returned by analyze tool + */ +server.tool('saveAnalysisResults', TOOL_DESCRIPTIONS.SAVE_RESULTS, TOOL_SCHEMAS.SAVE_RESULTS, async (args) => { + return await saveResultsTool.execute(args); +}); +/** + * dashboard - Start the web dashboard (same as CLI 'pr-agent dashboard') + */ +server.tool('dashboard', TOOL_DESCRIPTIONS.DASHBOARD, TOOL_SCHEMAS.DASHBOARD, async (args) => { + return await dashboardTool.execute(args, __dirname); +}); +// Main entry point +async function main() { + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error('PR Agent MCP Server started - LLM-agnostic mode with PROMPT_ONLY'); +} +main().catch((error) => { + console.error('Fatal error:', error); + process.exit(1); +}); +//# sourceMappingURL=server.js.map \ No newline at end of file diff --git a/dist/mcp/server.js.map b/dist/mcp/server.js.map new file mode 100644 index 0000000..c4f3726 --- /dev/null +++ b/dist/mcp/server.js.map @@ -0,0 +1 @@ +{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,sCAAsC;AACtC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,2CAA2C;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,oBAAoB;AACpB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,eAAe;IACrB,OAAO,EAAE,kBAAkB;CAC5B,CAAC,CAAC;AAEH,6BAA6B;AAC7B,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,CAAC;AAEhD,6CAA6C;AAC7C,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,gBAAgB,CAAC,CAAC;AACtD,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;AAC9C,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,gBAAgB,CAAC,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,CAAC,IAAI,CACT,SAAS,EACT,iBAAiB,CAAC,OAAO,EACzB,YAAY,CAAC,OAAO,EACpB,KAAK,EAAE,IAAI,EAAE,EAAE;IACb,OAAO,MAAM,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC,CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,iBAAiB,CAAC,YAAY,EAC9B,YAAY,CAAC,YAAY,EACzB,KAAK,EAAE,IAAI,EAAE,EAAE;IACb,OAAO,MAAM,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC,CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,IAAI,CACT,WAAW,EACX,iBAAiB,CAAC,SAAS,EAC3B,YAAY,CAAC,SAAS,EACtB,KAAK,EAAE,IAAI,EAAE,EAAE;IACb,OAAO,MAAM,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AACtD,CAAC,CACF,CAAC;AAEF,mBAAmB;AACnB,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;AACpF,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/mcp/services/dashboard.service.d.ts b/dist/mcp/services/dashboard.service.d.ts new file mode 100644 index 0000000..c4cf2d9 --- /dev/null +++ b/dist/mcp/services/dashboard.service.d.ts @@ -0,0 +1,34 @@ +/** + * Dashboard Service + * Manages the HTTP dashboard server + * Single Responsibility: Dashboard server lifecycle + */ +import type { DashboardServerState } from '../types.js'; +export declare class DashboardService { + private state; + /** + * Get current server state + */ + getState(): DashboardServerState; + /** + * Check if dashboard is running + */ + isRunning(): boolean; + /** + * Check if dashboard is running on specific port + */ + isRunningOnPort(port: number): boolean; + /** + * Start dashboard server + * @throws Error if server fails to start + */ + start(port: number, dirname: string): Promise; + /** + * Stop dashboard server + */ + stop(): void; + /** + * Start dashboard in background (non-blocking, swallow errors) + */ + startInBackground(port: number, dirname: string): Promise; +} diff --git a/dist/mcp/services/dashboard.service.js b/dist/mcp/services/dashboard.service.js new file mode 100644 index 0000000..a18d807 --- /dev/null +++ b/dist/mcp/services/dashboard.service.js @@ -0,0 +1,114 @@ +/** + * Dashboard Service + * Manages the HTTP dashboard server + * Single Responsibility: Dashboard server lifecycle + */ +import express from 'express'; +import path from 'path'; +import * as fs from 'fs'; +import { getDashboardStats, getRecentAnalyses } from '../../db/index.js'; +import { DASHBOARD_API_STATS_PATH, DASHBOARD_CATCH_ALL_PATH, ERROR_MESSAGES, SUCCESS_MESSAGES, } from '../constants.js'; +export class DashboardService { + state = { + httpServer: null, + port: null, + }; + /** + * Get current server state + */ + getState() { + return { ...this.state }; + } + /** + * Check if dashboard is running + */ + isRunning() { + return this.state.httpServer !== null && this.state.port !== null; + } + /** + * Check if dashboard is running on specific port + */ + isRunningOnPort(port) { + return this.isRunning() && this.state.port === port; + } + /** + * Start dashboard server + * @throws Error if server fails to start + */ + async start(port, dirname) { + // If already running on this port, do nothing + if (this.isRunningOnPort(port)) { + return; + } + // Stop existing server if running on different port + if (this.isRunning()) { + this.stop(); + } + return new Promise((resolve, reject) => { + const app = express(); + // Resolve public directory + const publicDir = path.resolve(dirname, '../public'); + const srcPublicDir = path.resolve(dirname, '../../src/public'); + const staticDir = fs.existsSync(publicDir) ? publicDir : srcPublicDir; + app.use(express.static(staticDir)); + // API Routes + app.get(DASHBOARD_API_STATS_PATH, (req, res) => { + try { + const stats = getDashboardStats(); + const recent = getRecentAnalyses(); + res.json({ stats, recent }); + } + catch (error) { + res.status(500).json({ error: 'Failed to fetch stats' }); + } + }); + app.get(DASHBOARD_CATCH_ALL_PATH, (req, res) => { + res.sendFile(path.join(staticDir, 'index.html')); + }); + const httpServer = app.listen(port, () => { + this.state.httpServer = httpServer; + this.state.port = port; + console.error(SUCCESS_MESSAGES.DASHBOARD_STARTED(port)); + // Open browser + import('open') + .then((openModule) => { + openModule.default(`http://localhost:${port}`).catch((err) => { + console.error('[MCP Server] Could not open browser:', err.message); + }); + }) + .catch((err) => { + console.error('[MCP Server] Could not import open module:', err.message); + }); + resolve(); + }); + httpServer.on('error', (err) => { + reject(new Error(err.code === 'EADDRINUSE' + ? ERROR_MESSAGES.DASHBOARD_PORT_IN_USE(port) + : ERROR_MESSAGES.DASHBOARD_START_FAILED(err.message))); + }); + }); + } + /** + * Stop dashboard server + */ + stop() { + if (this.state.httpServer) { + this.state.httpServer.close(); + this.state.httpServer = null; + this.state.port = null; + } + } + /** + * Start dashboard in background (non-blocking, swallow errors) + */ + async startInBackground(port, dirname) { + try { + await this.start(port, dirname); + } + catch (error) { + console.error('[MCP Server] Failed to start dashboard:', error.message); + // Don't throw - background operation should not block analysis + } + } +} +//# sourceMappingURL=dashboard.service.js.map \ No newline at end of file diff --git a/dist/mcp/services/dashboard.service.js.map b/dist/mcp/services/dashboard.service.js.map new file mode 100644 index 0000000..d446bc1 --- /dev/null +++ b/dist/mcp/services/dashboard.service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dashboard.service.js","sourceRoot":"","sources":["../../../src/mcp/services/dashboard.service.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/mcp/services/diff-parser.service.d.ts b/dist/mcp/services/diff-parser.service.d.ts new file mode 100644 index 0000000..a9e8d56 --- /dev/null +++ b/dist/mcp/services/diff-parser.service.d.ts @@ -0,0 +1,25 @@ +/** + * Diff Parser Service + * Parses git diff output into structured file metadata + * Single Responsibility: Diff parsing and file extraction + */ +import type { DiffFileMetadata } from '../types.js'; +export declare class DiffParserService { + /** + * Parse diff string into file metadata + * Extracts file paths, additions, deletions, and status + */ + static parseDiffFiles(diff: string): DiffFileMetadata[]; + /** + * Calculate total additions from diff files + */ + static getTotalAdditions(files: DiffFileMetadata[]): number; + /** + * Calculate total deletions from diff files + */ + static getTotalDeletions(files: DiffFileMetadata[]): number; + /** + * Get unique languages from file paths + */ + static getLanguagesFromFiles(files: DiffFileMetadata[]): string[]; +} diff --git a/dist/mcp/services/diff-parser.service.js b/dist/mcp/services/diff-parser.service.js new file mode 100644 index 0000000..6263c74 --- /dev/null +++ b/dist/mcp/services/diff-parser.service.js @@ -0,0 +1,63 @@ +/** + * Diff Parser Service + * Parses git diff output into structured file metadata + * Single Responsibility: Diff parsing and file extraction + */ +import { GIT_PATTERNS } from '../constants.js'; +export class DiffParserService { + /** + * Parse diff string into file metadata + * Extracts file paths, additions, deletions, and status + */ + static parseDiffFiles(diff) { + const files = []; + const filePattern = new RegExp(GIT_PATTERNS.FILE_DIFF_HEADER); + let match; + while ((match = filePattern.exec(diff)) !== null) { + const filePath = match[2] !== '/dev/null' ? match[2] : match[1]; + const isNew = match[1] === '/dev/null' || match[1].startsWith('dev/null'); + const isDeleted = match[2] === '/dev/null'; + // Count additions and deletions for this file + const fileStart = match.index; + const nextFileMatch = filePattern.exec(diff); + const fileEnd = nextFileMatch ? nextFileMatch.index : diff.length; + filePattern.lastIndex = match.index + 1; // Reset to continue from after current match + const fileContent = diff.substring(fileStart, fileEnd); + const additions = (fileContent.match(/^\+[^+]/gm) || []).length; + const deletions = (fileContent.match(/^-[^-]/gm) || []).length; + files.push({ + path: filePath, + additions, + deletions, + status: isNew ? 'added' : isDeleted ? 'deleted' : 'modified', + }); + } + return files; + } + /** + * Calculate total additions from diff files + */ + static getTotalAdditions(files) { + return files.reduce((sum, f) => sum + (f.additions || 0), 0); + } + /** + * Calculate total deletions from diff files + */ + static getTotalDeletions(files) { + return files.reduce((sum, f) => sum + (f.deletions || 0), 0); + } + /** + * Get unique languages from file paths + */ + static getLanguagesFromFiles(files) { + const extensions = new Set(); + for (const file of files) { + const ext = file.path.split('.').pop()?.toLowerCase(); + if (ext) { + extensions.add(ext); + } + } + return Array.from(extensions); + } +} +//# sourceMappingURL=diff-parser.service.js.map \ No newline at end of file diff --git a/dist/mcp/services/diff-parser.service.js.map b/dist/mcp/services/diff-parser.service.js.map new file mode 100644 index 0000000..e127117 --- /dev/null +++ b/dist/mcp/services/diff-parser.service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"diff-parser.service.js","sourceRoot":"","sources":["../../../src/mcp/services/diff-parser.service.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/mcp/services/formatter.service.d.ts b/dist/mcp/services/formatter.service.d.ts new file mode 100644 index 0000000..a86a0c5 --- /dev/null +++ b/dist/mcp/services/formatter.service.d.ts @@ -0,0 +1,12 @@ +/** + * Formatter Service + * Formats analysis output for MCP responses + * Single Responsibility: Output formatting and presentation + */ +import type { AnalysisOutputOptions } from '../types.js'; +export declare class FormatterService { + /** + * Format complete analysis output for MCP response + */ + static formatAnalysisOutput(options: AnalysisOutputOptions): string; +} diff --git a/dist/mcp/services/formatter.service.js b/dist/mcp/services/formatter.service.js new file mode 100644 index 0000000..ad68ebe --- /dev/null +++ b/dist/mcp/services/formatter.service.js @@ -0,0 +1,126 @@ +/** + * Formatter Service + * Formats analysis output for MCP responses + * Single Responsibility: Output formatting and presentation + */ +import { OutputFormatter } from '../../utils/output-formatter.js'; +import { PROMPT_STEP_EMOJIS, DEFAULT_PROMPT_EMOJI, DEFAULT_PROMPT_LIMIT_VERBOSE, DEFAULT_PROMPT_LIMIT_NORMAL, INSTRUCTIONS, PEER_REVIEW_ERROR_CAUSES, ERROR_MESSAGES, } from '../constants.js'; +export class FormatterService { + /** + * Format complete analysis output for MCP response + */ + static formatAnalysisOutput(options) { + const lines = []; + // Header (verbose only) + if (options.verbose) { + lines.push(`# 🤖 PR Agent Analysis\n`); + lines.push(`**Repository:** ${options.repoInfo.owner}/${options.repoInfo.name}`); + lines.push(`**Branch:** ${options.currentBranch} → ${options.baseBranch}`); + lines.push(`**PR Title:** ${options.title || 'Untitled'}`); + lines.push(`**Peer Review:** ${options.peerReviewEnabled ? '✅ Enabled' : '❌ Disabled'}`); + lines.push(`**Prompts to execute:** ${options.allPrompts.length}\n`); + lines.push(`---\n`); + } + // Static Analysis Results + lines.push(`## 📊 Static Analysis Results\n`); + if (options.staticAnalysis) { + const formatter = new OutputFormatter({ mode: 'markdown', verbose: options.verbose }); + const staticOutput = formatter.formatStaticAnalysis(options.staticAnalysis); + if (staticOutput) { + lines.push(staticOutput); + lines.push('\n'); + } + } + lines.push(`---\n\n`); + // Project Classification + if (options.projectClassification) { + const formatter = new OutputFormatter({ mode: 'markdown', verbose: options.verbose }); + const classificationOutput = formatter.formatProjectClassification(options.projectClassification); + if (classificationOutput) { + lines.push(classificationOutput); + lines.push('\n'); + } + lines.push(`---\n\n`); + } + // DevOps Cost Estimates + lines.push(`## 💰 DevOps Cost Estimates\n`); + if (options.devOpsCostEstimates && options.devOpsCostEstimates.length > 0) { + lines.push(`**Total Estimated Monthly Cost:** $${options.totalDevOpsCost?.toFixed(2) || '0.00'}\n`); + options.devOpsCostEstimates.forEach(estimate => { + const emoji = estimate.confidence === 'high' ? '🟢' : estimate.confidence === 'medium' ? '🟡' : '🔴'; + lines.push(`### ${estimate.resourceType}\n`); + if (estimate.details) { + lines.push(`${emoji} ${estimate.resourceType.toUpperCase()}: ~$${estimate.estimatedNewCost.toFixed(2)}/month`); + lines.push(` ${estimate.details}\n`); + } + }); + lines.push(`\n📊 Total Estimated Impact: ~$${options.totalDevOpsCost?.toFixed(2) || '0.00'}/month\n`); + lines.push(`\n⚠️ Estimates are approximate. Actual costs depend on usage and configuration.\n`); + } + else { + lines.push(`No DevOps infrastructure changes detected.\n`); + } + lines.push(`\n---\n`); + // Peer Review Error (if occurred) + if (options.peerReviewEnabled && options.peerReviewError) { + lines.push(`\n---\n`); + lines.push(`## ⚠️ Peer Review Error\n`); + lines.push(ERROR_MESSAGES.PEER_REVIEW_FAILED(options.peerReviewError)); + lines.push('\n'); + lines.push(`**Possible causes:**`); + PEER_REVIEW_ERROR_CAUSES.forEach((cause) => lines.push(cause)); + lines.push('\n'); + lines.push(`Analysis will continue with base prompts only.\n`); + } + // LLM Analysis Workflow + lines.push(`---\n`); + lines.push(`## ⚡ LLM Analysis Workflow\n`); + lines.push(INSTRUCTIONS.PROMPT_EXECUTION_WARNING); + lines.push('\n'); + lines.push(`Execute the following ${options.allPrompts.length} prompts sequentially:\n`); + // Format each prompt + options.allPrompts.forEach((prompt, i) => { + const stepEmoji = PROMPT_STEP_EMOJIS[prompt.step] || DEFAULT_PROMPT_EMOJI; + lines.push(`### ${stepEmoji} Step ${i + 1}: ${prompt.step}\n`); + if (options.verbose) { + lines.push(`**Instructions:** ${prompt.instructions}\n`); + } + lines.push('**Prompt:**\n```'); + const promptLimit = options.verbose + ? DEFAULT_PROMPT_LIMIT_VERBOSE + : DEFAULT_PROMPT_LIMIT_NORMAL; + lines.push(prompt.prompt.substring(0, promptLimit)); + if (prompt.prompt.length > promptLimit) { + lines.push('\n... (truncated for display)'); + } + lines.push('\n```\n'); + lines.push('---\n'); + }); + // Next Steps + lines.push(`## 💾 Next Steps\n`); + lines.push(INSTRUCTIONS.NEXT_STEPS_HEADER); + INSTRUCTIONS.NEXT_STEPS(options.allPrompts.length).forEach((step) => { + lines.push(step); + }); + lines.push('\n'); + lines.push(INSTRUCTIONS.EXPECTED_TOKEN_USAGE); + if (options.verbose) { + lines.push('\n'); + lines.push(`**Save parameters:**`); + lines.push(`- title: "${options.title || 'Untitled'}"`); + lines.push(`- repoOwner: "${options.repoInfo.owner}"`); + lines.push(`- repoName: "${options.repoInfo.name}"`); + lines.push(`- complexity: (from summary step)`); + lines.push(`- risksCount: (from risk detection step)`); + lines.push(`- risks: (from risk detection step)`); + lines.push(`- recommendations: (from summary step)`); + if (options.peerReviewEnabled) { + lines.push(`- peerReviewEnabled: true`); + lines.push(`- ticketKey, acCompliancePercentage, etc.: (from peer review steps)`); + } + lines.push(`\n📊 Dashboard: http://localhost:3000`); + } + return lines.join('\n'); + } +} +//# sourceMappingURL=formatter.service.js.map \ No newline at end of file diff --git a/dist/mcp/services/formatter.service.js.map b/dist/mcp/services/formatter.service.js.map new file mode 100644 index 0000000..be26ddd --- /dev/null +++ b/dist/mcp/services/formatter.service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"formatter.service.js","sourceRoot":"","sources":["../../../src/mcp/services/formatter.service.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/mcp/services/git.service.d.ts b/dist/mcp/services/git.service.d.ts new file mode 100644 index 0000000..e455fd2 --- /dev/null +++ b/dist/mcp/services/git.service.d.ts @@ -0,0 +1,33 @@ +/** + * Git Service + * Handles all git operations for the MCP server + * Single Responsibility: Git repository interactions + */ +import type { RepoInfo, GitOperationOptions } from '../types.js'; +export declare class GitService { + /** + * Get git diff output + * @throws Error if git command fails + */ + static getGitDiff(command: string, options?: GitOperationOptions): string; + /** + * Get current branch name + */ + static getCurrentBranch(cwd?: string): string; + /** + * Extract repository owner and name from git remote URL + */ + static getRepoInfo(cwd?: string): RepoInfo; + /** + * Get PR title from latest commit message + */ + static getPRTitle(cwd?: string): string | undefined; + /** + * Get git author from latest commit + */ + static getGitAuthor(cwd?: string): string; + /** + * Get recent commit messages for ticket extraction + */ + static getCommitMessages(cwd?: string, limit?: number): string[]; +} diff --git a/dist/mcp/services/git.service.js b/dist/mcp/services/git.service.js new file mode 100644 index 0000000..757f8b2 --- /dev/null +++ b/dist/mcp/services/git.service.js @@ -0,0 +1,116 @@ +/** + * Git Service + * Handles all git operations for the MCP server + * Single Responsibility: Git repository interactions + */ +import { execSync } from 'child_process'; +import { DEFAULT_GIT_LOG_LIMIT, DEFAULT_MAX_BUFFER, GIT_PATTERNS, DEFAULTS, } from '../constants.js'; +export class GitService { + /** + * Get git diff output + * @throws Error if git command fails + */ + static getGitDiff(command, options = {}) { + try { + const diff = execSync(command, { + encoding: 'utf-8', + cwd: options.cwd || process.cwd(), + maxBuffer: options.maxBuffer || DEFAULT_MAX_BUFFER, + shell: true, + }); + return diff.trim(); + } + catch (error) { + throw new Error(`Failed to get diff: ${error.message}`); + } + } + /** + * Get current branch name + */ + static getCurrentBranch(cwd) { + try { + return execSync('git rev-parse --abbrev-ref HEAD', { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + }).trim(); + } + catch { + return DEFAULTS.BRANCH_NAME; + } + } + /** + * Extract repository owner and name from git remote URL + */ + static getRepoInfo(cwd) { + try { + const remoteUrl = execSync('git remote get-url origin', { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + }).trim(); + // Try SSH format + const sshMatch = remoteUrl.match(GIT_PATTERNS.SSH_REMOTE); + if (sshMatch) { + return { owner: sshMatch[1], name: sshMatch[2] }; + } + // Try HTTPS format + const httpsMatch = remoteUrl.match(GIT_PATTERNS.HTTPS_REMOTE); + if (httpsMatch) { + return { owner: httpsMatch[1], name: httpsMatch[2] }; + } + return { owner: DEFAULTS.REPO_OWNER, name: DEFAULTS.REPO_NAME }; + } + catch { + return { owner: DEFAULTS.REPO_OWNER, name: DEFAULTS.REPO_NAME }; + } + } + /** + * Get PR title from latest commit message + */ + static getPRTitle(cwd) { + try { + const title = execSync('git log -1 --pretty=%s', { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + }).trim(); + return title || undefined; + } + catch { + return undefined; + } + } + /** + * Get git author from latest commit + */ + static getGitAuthor(cwd) { + try { + return execSync('git log -1 --pretty=%an', { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + }).trim(); + } + catch { + return DEFAULTS.AUTHOR; + } + } + /** + * Get recent commit messages for ticket extraction + */ + static getCommitMessages(cwd, limit = DEFAULT_GIT_LOG_LIMIT) { + try { + const commits = execSync(`git log --oneline -${limit}`, { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + }); + return commits.trim().split('\n').filter(Boolean); + } + catch { + return []; + } + } +} +//# sourceMappingURL=git.service.js.map \ No newline at end of file diff --git a/dist/mcp/services/git.service.js.map b/dist/mcp/services/git.service.js.map new file mode 100644 index 0000000..b3220ec --- /dev/null +++ b/dist/mcp/services/git.service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"git.service.js","sourceRoot":"","sources":["../../../src/mcp/services/git.service.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/mcp/services/index.d.ts b/dist/mcp/services/index.d.ts new file mode 100644 index 0000000..2c7157f --- /dev/null +++ b/dist/mcp/services/index.d.ts @@ -0,0 +1,10 @@ +/** + * MCP Services + * Central export point for all service classes + */ +export { GitService } from './git.service.js'; +export { DiffParserService } from './diff-parser.service.js'; +export { TicketExtractorService } from './ticket-extractor.service.js'; +export { FormatterService } from './formatter.service.js'; +export { DashboardService } from './dashboard.service.js'; +export { PeerReviewService } from './peer-review.service.js'; diff --git a/dist/mcp/services/index.js b/dist/mcp/services/index.js new file mode 100644 index 0000000..8c3f913 --- /dev/null +++ b/dist/mcp/services/index.js @@ -0,0 +1,11 @@ +/** + * MCP Services + * Central export point for all service classes + */ +export { GitService } from './git.service.js'; +export { DiffParserService } from './diff-parser.service.js'; +export { TicketExtractorService } from './ticket-extractor.service.js'; +export { FormatterService } from './formatter.service.js'; +export { DashboardService } from './dashboard.service.js'; +export { PeerReviewService } from './peer-review.service.js'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/mcp/services/index.js.map b/dist/mcp/services/index.js.map new file mode 100644 index 0000000..a5e2ae9 --- /dev/null +++ b/dist/mcp/services/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/services/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC"} \ No newline at end of file diff --git a/dist/mcp/services/peer-review.service.d.ts b/dist/mcp/services/peer-review.service.d.ts new file mode 100644 index 0000000..965e088 --- /dev/null +++ b/dist/mcp/services/peer-review.service.d.ts @@ -0,0 +1,14 @@ +/** + * Peer Review Service + * Orchestrates peer review analysis with Jira integration + * Single Responsibility: Peer review workflow coordination + */ +import { type PeerReviewResult } from '../../issue-tracker/index.js'; +import type { PeerReviewContext } from '../types.js'; +export declare class PeerReviewService { + /** + * Run peer review analysis in PROMPT_ONLY mode + * Returns prompts for the calling LLM to execute + */ + static runPeerReview(context: PeerReviewContext): Promise; +} diff --git a/dist/mcp/services/peer-review.service.js b/dist/mcp/services/peer-review.service.js new file mode 100644 index 0000000..93af539 --- /dev/null +++ b/dist/mcp/services/peer-review.service.js @@ -0,0 +1,78 @@ +/** + * Peer Review Service + * Orchestrates peer review analysis with Jira integration + * Single Responsibility: Peer review workflow coordination + */ +import { execSync } from 'child_process'; +import { createPeerReviewIntegration, PeerReviewMode, } from '../../issue-tracker/index.js'; +import { DiffParserService } from './diff-parser.service.js'; +export class PeerReviewService { + /** + * Run peer review analysis in PROMPT_ONLY mode + * Returns prompts for the calling LLM to execute + */ + static async runPeerReview(context) { + try { + // Use PROMPT_ONLY mode - no LLM needed, returns prompts for calling LLM to execute + const peerReviewConfig = context.config.peerReview || {}; + const integration = createPeerReviewIntegration(peerReviewConfig, PeerReviewMode.PROMPT_ONLY); + if (!integration.isEnabled()) { + console.error('[MCP Server] Peer Review enabled but not configured'); + if (context.verbose) { + console.error('[MCP Server] Set peerReview.useMcp=true in config'); + } + return null; + } + // Get branch name for ticket extraction + let branchName; + try { + branchName = execSync('git rev-parse --abbrev-ref HEAD', { + encoding: 'utf-8', + cwd: context.workDir, + shell: true, + }).trim(); + } + catch { + // Ignore - branch name is optional + } + // Get commit messages for ticket extraction + let commitMessages = []; + try { + const commits = execSync('git log --oneline -10', { + encoding: 'utf-8', + cwd: context.workDir, + shell: true, + }); + commitMessages = commits.trim().split('\n'); + } + catch { + // Ignore + } + // Parse diff to get file info + const files = DiffParserService.parseDiffFiles(context.diff); + console.error('[MCP Server] Running peer review analysis...'); + // Run peer review analysis + const result = await integration.analyze({ + prTitle: context.title || 'Untitled PR', + prDescription: undefined, + branchName, + commitMessages, + diff: context.diff, + files, + prSummary: context.prAnalysisResult.summary, + prRisks: context.prAnalysisResult.overallRisks, + prComplexity: context.prAnalysisResult.overallComplexity, + }); + console.error('[MCP Server] Peer review analysis complete'); + return result; + } + catch (error) { + console.error('[MCP Server] Peer review failed:', error.message); + if (context.verbose) { + console.error('[MCP Server] Error details:', error.stack); + } + return null; + } + } +} +//# sourceMappingURL=peer-review.service.js.map \ No newline at end of file diff --git a/dist/mcp/services/peer-review.service.js.map b/dist/mcp/services/peer-review.service.js.map new file mode 100644 index 0000000..b1c35c7 --- /dev/null +++ b/dist/mcp/services/peer-review.service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"peer-review.service.js","sourceRoot":"","sources":["../../../src/mcp/services/peer-review.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,2BAA2B,EAC3B,cAAc,GAEf,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,OAAO,iBAAiB;IAC5B;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,OAA0B;QACnD,IAAI,CAAC;YACH,mFAAmF;YACnF,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;YACzD,MAAM,WAAW,GAAG,2BAA2B,CAC7C,gBAAgB,EAChB,cAAc,CAAC,WAAW,CAC3B,CAAC;YAEF,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,CAAC;gBAC7B,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;gBACrE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACpB,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;gBACrE,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;YAED,wCAAwC;YACxC,IAAI,UAA8B,CAAC;YACnC,IAAI,CAAC;gBACH,UAAU,GAAG,QAAQ,CAAC,iCAAiC,EAAE;oBACvD,QAAQ,EAAE,OAAO;oBACjB,GAAG,EAAE,OAAO,CAAC,OAAO;oBACpB,KAAK,EAAE,IAAI;iBACL,CAAC,CAAC,IAAI,EAAE,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;YACrC,CAAC;YAED,4CAA4C;YAC5C,IAAI,cAAc,GAAa,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,QAAQ,CAAC,uBAAuB,EAAE;oBAChD,QAAQ,EAAE,OAAO;oBACjB,GAAG,EAAE,OAAO,CAAC,OAAO;oBACpB,KAAK,EAAE,IAAI;iBACL,CAAC,CAAC;gBACV,cAAc,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC9C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,8BAA8B;YAC9B,MAAM,KAAK,GAAG,iBAAiB,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAE7D,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAE9D,2BAA2B;YAC3B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC;gBACvC,OAAO,EAAE,OAAO,CAAC,KAAK,IAAI,aAAa;gBACvC,aAAa,EAAE,SAAS;gBACxB,UAAU;gBACV,cAAc;gBACd,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,KAAK;gBACL,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC,OAAO;gBAC3C,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,YAAY;gBAC9C,YAAY,EAAE,OAAO,CAAC,gBAAgB,CAAC,iBAAiB;aACzD,CAAC,CAAC;YAEH,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC5D,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YACjE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YAC5D,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/dist/mcp/services/ticket-extractor.service.d.ts b/dist/mcp/services/ticket-extractor.service.d.ts new file mode 100644 index 0000000..fb65302 --- /dev/null +++ b/dist/mcp/services/ticket-extractor.service.d.ts @@ -0,0 +1,28 @@ +/** + * Ticket Extractor Service + * Extracts ticket references from PR metadata + * Single Responsibility: Ticket identification and extraction + */ +import type { TicketReference } from '../types.js'; +export declare class TicketExtractorService { + /** + * Extract ticket references from all PR metadata sources + */ + static extractTicketReferences(title: string | undefined, branchName: string, commitMessages: string[], defaultProject?: string): TicketReference[]; + /** + * Extract ticket keys from text using pattern matching + */ + private static extractFromText; + /** + * Get the primary (highest confidence) ticket reference + */ + static getPrimaryTicket(references: TicketReference[]): TicketReference | undefined; + /** + * Check if any tickets were found + */ + static hasTickets(references: TicketReference[]): boolean; + /** + * Filter tickets by minimum confidence threshold + */ + static filterByConfidence(references: TicketReference[], minConfidence: number): TicketReference[]; +} diff --git a/dist/mcp/services/ticket-extractor.service.js b/dist/mcp/services/ticket-extractor.service.js new file mode 100644 index 0000000..c94775f --- /dev/null +++ b/dist/mcp/services/ticket-extractor.service.js @@ -0,0 +1,71 @@ +/** + * Ticket Extractor Service + * Extracts ticket references from PR metadata + * Single Responsibility: Ticket identification and extraction + */ +// Default Jira ticket pattern: PROJ-123 +const DEFAULT_TICKET_PATTERN = /([A-Z][A-Z0-9]+-\d+)/g; +export class TicketExtractorService { + /** + * Extract ticket references from all PR metadata sources + */ + static extractTicketReferences(title, branchName, commitMessages, defaultProject) { + const references = new Map(); + // Extract from title (highest confidence - 95%) + if (title) { + this.extractFromText(title, 'title', 95, references, defaultProject); + } + // Extract from branch name (high confidence - 90%) + this.extractFromText(branchName, 'branch', 90, references, defaultProject); + // Extract from commit messages (lower confidence - 70%) + for (const message of commitMessages) { + this.extractFromText(message, 'commit', 70, references, defaultProject); + } + // Sort by confidence (highest first) + return Array.from(references.values()).sort((a, b) => b.confidence - a.confidence); + } + /** + * Extract ticket keys from text using pattern matching + */ + static extractFromText(text, source, baseConfidence, references, defaultProject) { + // Reset regex state + DEFAULT_TICKET_PATTERN.lastIndex = 0; + let match; + while ((match = DEFAULT_TICKET_PATTERN.exec(text)) !== null) { + const key = match[1].toUpperCase(); + // If default project is set, only include tickets from that project + if (defaultProject && !key.startsWith(defaultProject)) { + continue; + } + // Skip if we already have this reference with higher confidence + const existing = references.get(key); + if (existing && existing.confidence >= baseConfidence) { + continue; + } + references.set(key, { + key, + source, + confidence: baseConfidence, + }); + } + } + /** + * Get the primary (highest confidence) ticket reference + */ + static getPrimaryTicket(references) { + return references.length > 0 ? references[0] : undefined; + } + /** + * Check if any tickets were found + */ + static hasTickets(references) { + return references.length > 0; + } + /** + * Filter tickets by minimum confidence threshold + */ + static filterByConfidence(references, minConfidence) { + return references.filter((ref) => ref.confidence >= minConfidence); + } +} +//# sourceMappingURL=ticket-extractor.service.js.map \ No newline at end of file diff --git a/dist/mcp/services/ticket-extractor.service.js.map b/dist/mcp/services/ticket-extractor.service.js.map new file mode 100644 index 0000000..9211b39 --- /dev/null +++ b/dist/mcp/services/ticket-extractor.service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ticket-extractor.service.js","sourceRoot":"","sources":["../../../src/mcp/services/ticket-extractor.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,wCAAwC;AACxC,MAAM,sBAAsB,GAAG,uBAAuB,CAAC;AAEvD,MAAM,OAAO,sBAAsB;IACjC;;OAEG;IACH,MAAM,CAAC,uBAAuB,CAC5B,KAAyB,EACzB,UAAkB,EAClB,cAAwB,EACxB,cAAuB;QAEvB,MAAM,UAAU,GAAG,IAAI,GAAG,EAA2B,CAAC;QAEtD,gDAAgD;QAChD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;QACvE,CAAC;QAED,mDAAmD;QACnD,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;QAE3E,wDAAwD;QACxD,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;YACrC,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;QAC1E,CAAC;QAED,qCAAqC;QACrC,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CACzC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CACtC,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,eAAe,CAC5B,IAAY,EACZ,MAAiC,EACjC,cAAsB,EACtB,UAAwC,EACxC,cAAuB;QAEvB,oBAAoB;QACpB,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;QAErC,IAAI,KAAK,CAAC;QACV,OAAO,CAAC,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5D,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YAEnC,oEAAoE;YACpE,IAAI,cAAc,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;gBACtD,SAAS;YACX,CAAC;YAED,gEAAgE;YAChE,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACrC,IAAI,QAAQ,IAAI,QAAQ,CAAC,UAAU,IAAI,cAAc,EAAE,CAAC;gBACtD,SAAS;YACX,CAAC;YAED,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE;gBAClB,GAAG;gBACH,MAAM;gBACN,UAAU,EAAE,cAAc;aAC3B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,UAA6B;QACnD,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,UAA6B;QAC7C,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,kBAAkB,CACvB,UAA6B,EAC7B,aAAqB;QAErB,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,IAAI,aAAa,CAAC,CAAC;IACrE,CAAC;CACF"} \ No newline at end of file diff --git a/dist/mcp/tools/analyze-tool.d.ts b/dist/mcp/tools/analyze-tool.d.ts new file mode 100644 index 0000000..02e0c38 --- /dev/null +++ b/dist/mcp/tools/analyze-tool.d.ts @@ -0,0 +1,20 @@ +/** + * Analyze Tool Handler + * Handles the 'analyze' MCP tool + * Single Responsibility: Orchestrate PR analysis workflow + */ +import type { McpToolResponse } from '../types.js'; +import { DashboardService } from '../services/index.js'; +export interface AnalyzeToolArgs { + branch?: string; + staged?: boolean; + title?: string; + cwd?: string; + verbose?: boolean; + archDocs?: boolean; +} +export declare class AnalyzeTool { + private dashboardService; + constructor(dashboardService: DashboardService); + execute(args: AnalyzeToolArgs): Promise; +} diff --git a/dist/mcp/tools/analyze-tool.js b/dist/mcp/tools/analyze-tool.js new file mode 100644 index 0000000..8da64c6 --- /dev/null +++ b/dist/mcp/tools/analyze-tool.js @@ -0,0 +1,201 @@ +/** + * Analyze Tool Handler + * Handles the 'analyze' MCP tool + * Single Responsibility: Orchestrate PR analysis workflow + */ +import { PRAnalyzerAgent } from '../../agents/pr-analyzer-agent.js'; +import { loadUserConfig } from '../../cli/utils/config-loader.js'; +import { resolveDefaultBranch } from '../../utils/branch-resolver.js'; +import { ExecutionMode as ExecutionModeEnum } from '../../types/agent.types.js'; +import { GitService, TicketExtractorService, FormatterService, PeerReviewService, } from '../services/index.js'; +import { ERROR_MESSAGES, DEFAULT_DASHBOARD_PORT, DEFAULTS } from '../constants.js'; +import { analyzeDevOpsFiles } from '../../tools/devops-cost-estimator.js'; +import { parseDiff } from '../../tools/pr-analysis-tools.js'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; +// __dirname workaround for ES modules +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +export class AnalyzeTool { + dashboardService; + constructor(dashboardService) { + this.dashboardService = dashboardService; + } + async execute(args) { + const workDir = args.cwd || process.cwd(); + const verbose = args.verbose || false; + try { + // Load configuration + let config = {}; + try { + config = await loadUserConfig(verbose, false); + } + catch (e) { + // Config not found is OK + } + // Resolve base branch + let baseBranch = args.branch; + if (!baseBranch && !args.staged) { + try { + const branchResult = await resolveDefaultBranch({ + configBranch: config.git?.defaultBranch, + githubToken: process.env.GITHUB_TOKEN, + fallbackToGit: true, + }); + baseBranch = branchResult.branch; + } + catch { + baseBranch = DEFAULTS.DEFAULT_BRANCH; + } + } + // Get diff + let diff; + if (args.staged) { + diff = GitService.getGitDiff('git diff --staged', { cwd: workDir }); + } + else { + diff = GitService.getGitDiff(`git diff ${baseBranch}`, { cwd: workDir }); + } + const title = args.title || GitService.getPRTitle(workDir); + const currentBranch = GitService.getCurrentBranch(workDir); + const repoInfo = GitService.getRepoInfo(workDir); + // Check for changes + if (!diff) { + return { + content: [ + { + type: 'text', + text: ERROR_MESSAGES.NO_CHANGES(currentBranch, baseBranch || 'staged'), + }, + ], + }; + } + // Extract ticket references + const commitMessages = GitService.getCommitMessages(workDir); + const peerReviewEnabled = config.peerReview?.enabled ?? false; + if (verbose) { + console.error(`[MCP Server] Config loaded: peerReview.enabled=${peerReviewEnabled}, archDocs=${args.archDocs !== false}`); + } + const ticketRefs = TicketExtractorService.extractTicketReferences(title, currentBranch, commitMessages, config.peerReview?.defaultProject); + // Create PRAnalyzerAgent in PROMPT_ONLY mode + const agent = new PRAnalyzerAgent({ mode: ExecutionModeEnum.PROMPT_ONLY }); + // Run analysis to get prompts (no LLM execution) + const useArchDocs = args.archDocs !== false; + if (verbose) { + console.error('[MCP Server] Building analysis prompts in PROMPT_ONLY mode...'); + } + const analysisResult = await agent.analyze(diff, title, { summary: true, risks: true, complexity: true }, { + useArchDocs, + repoPath: workDir, + language: config.analysis?.language, + framework: config.analysis?.framework, + enableStaticAnalysis: config.analysis?.enableStaticAnalysis !== false, + }); + // DETERMINISTIC ANALYSIS: DevOps cost estimation (runs even in PROMPT_ONLY mode) + let devOpsCostEstimates; + let totalDevOpsCost = 0; + const parsedFiles = parseDiff(diff); + const filesForCostAnalysis = parsedFiles.map((f) => ({ path: f.path, diff: f.diff })); + if (verbose) { + console.error(`[MCP Server] Parsed ${parsedFiles.length} files for cost analysis`); + console.error(`[MCP Server] Sample file paths: ${parsedFiles.slice(0, 3).map((f) => f.path).join(', ')}`); + } + const costAnalysis = analyzeDevOpsFiles(filesForCostAnalysis); + if (verbose) { + console.error(`[MCP Server] Cost analysis complete: hasDevOpsChanges=${costAnalysis.hasDevOpsChanges}, estimates=${costAnalysis.estimates.length}`); + } + if (costAnalysis.hasDevOpsChanges && costAnalysis.estimates.length > 0) { + devOpsCostEstimates = costAnalysis.estimates; + totalDevOpsCost = costAnalysis.totalEstimatedCost; + console.error(`[MCP Server] DevOps costs: ${costAnalysis.estimates.length} resources (~$${totalDevOpsCost.toFixed(2)}/month)`); + } + else if (verbose) { + console.error(`[MCP Server] No DevOps costs found`); + } + if (verbose) { + console.error('[MCP Server] Analysis prompts built'); + console.error(` - mode: ${analysisResult.mode}`); + console.error(` - prompt count: ${analysisResult.mode === 'prompt_only' ? analysisResult.prompts.length : 'N/A'}`); + console.error(` - peer review: ${peerReviewEnabled ? 'enabled' : 'disabled'}`); + } + // Type guard + if (analysisResult.mode !== 'prompt_only') { + throw new Error('Expected prompt-only result in MCP mode'); + } + // Get peer review prompts if enabled + let peerReviewError; + if (peerReviewEnabled) { + try { + const peerReviewResult = await PeerReviewService.runPeerReview({ + config, + diff, + title, + prAnalysisResult: analysisResult, + verbose, + workDir, + }); + if (peerReviewResult && + peerReviewResult.mode === 'prompt_only' && + peerReviewResult.promptOnlyResult) { + analysisResult.prompts.push(...peerReviewResult.promptOnlyResult.prompts); + console.error(` - Peer review prompts: ${peerReviewResult.promptOnlyResult.prompts.length}`); + } + else if (peerReviewResult && peerReviewResult.error) { + peerReviewError = peerReviewResult.error; + console.error(`[MCP Server] Peer review failed: ${peerReviewError}`); + } + } + catch (error) { + peerReviewError = error.message; + console.error('[MCP Server] Peer review prompt building failed:', error.message); + if (verbose) { + console.error(error.stack); + } + } + } + // Format output + const outputOptions = { + verbose, + peerReviewEnabled, + peerReviewError, + allPrompts: analysisResult.prompts, + staticAnalysis: analysisResult.staticAnalysis, + devOpsCostEstimates, + totalDevOpsCost, + projectClassification: analysisResult.projectClassification, + repoInfo, + currentBranch, + baseBranch, + title, + }; + if (verbose && devOpsCostEstimates) { + console.error(`[MCP Server] Passing ${devOpsCostEstimates.length} cost estimates to formatter:`); + devOpsCostEstimates.forEach((est, i) => { + console.error(` [${i}] ${est.resourceType}: cost=$${est.estimatedNewCost}, details="${est.details}"`); + }); + } + const outputText = FormatterService.formatAnalysisOutput(outputOptions); + // Start dashboard in background + await this.dashboardService.startInBackground(DEFAULT_DASHBOARD_PORT, __dirname); + return { + content: [ + { + type: 'text', + text: outputText, + }, + ], + }; + } + catch (error) { + return { + content: [ + { + type: 'text', + text: ERROR_MESSAGES.ANALYSIS_FAILED(error.message), + }, + ], + }; + } + } +} +//# sourceMappingURL=analyze-tool.js.map \ No newline at end of file diff --git a/dist/mcp/tools/analyze-tool.js.map b/dist/mcp/tools/analyze-tool.js.map new file mode 100644 index 0000000..3722536 --- /dev/null +++ b/dist/mcp/tools/analyze-tool.js.map @@ -0,0 +1 @@ +{"version":3,"file":"analyze-tool.js","sourceRoot":"","sources":["../../../src/mcp/tools/analyze-tool.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/mcp/tools/dashboard-tool.d.ts b/dist/mcp/tools/dashboard-tool.d.ts new file mode 100644 index 0000000..cdfd0c5 --- /dev/null +++ b/dist/mcp/tools/dashboard-tool.d.ts @@ -0,0 +1,15 @@ +/** + * Dashboard Tool Handler + * Handles the 'dashboard' MCP tool + * Single Responsibility: Start/manage dashboard server + */ +import type { McpToolResponse } from '../types.js'; +import { DashboardService } from '../services/index.js'; +export interface DashboardToolArgs { + port?: number; +} +export declare class DashboardTool { + private dashboardService; + constructor(dashboardService: DashboardService); + execute(args: DashboardToolArgs, dirname: string): Promise; +} diff --git a/dist/mcp/tools/dashboard-tool.js b/dist/mcp/tools/dashboard-tool.js new file mode 100644 index 0000000..44dd234 --- /dev/null +++ b/dist/mcp/tools/dashboard-tool.js @@ -0,0 +1,48 @@ +/** + * Dashboard Tool Handler + * Handles the 'dashboard' MCP tool + * Single Responsibility: Start/manage dashboard server + */ +import { ERROR_MESSAGES, DEFAULT_DASHBOARD_PORT } from '../constants.js'; +export class DashboardTool { + dashboardService; + constructor(dashboardService) { + this.dashboardService = dashboardService; + } + async execute(args, dirname) { + const targetPort = args.port || DEFAULT_DASHBOARD_PORT; + // Check if already running on this port + if (this.dashboardService.isRunningOnPort(targetPort)) { + return { + content: [ + { + type: 'text', + text: ERROR_MESSAGES.DASHBOARD_ALREADY_RUNNING(targetPort), + }, + ], + }; + } + try { + await this.dashboardService.start(targetPort, dirname); + return { + content: [ + { + type: 'text', + text: `✅ Dashboard started successfully!\n\n📊 Access at: http://localhost:${targetPort}\n\nView PR analysis history, statistics, and insights.`, + }, + ], + }; + } + catch (error) { + return { + content: [ + { + type: 'text', + text: `❌ Failed to start dashboard: ${error.message}`, + }, + ], + }; + } + } +} +//# sourceMappingURL=dashboard-tool.js.map \ No newline at end of file diff --git a/dist/mcp/tools/dashboard-tool.js.map b/dist/mcp/tools/dashboard-tool.js.map new file mode 100644 index 0000000..c65cf41 --- /dev/null +++ b/dist/mcp/tools/dashboard-tool.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dashboard-tool.js","sourceRoot":"","sources":["../../../src/mcp/tools/dashboard-tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAMzE,MAAM,OAAO,aAAa;IAChB,gBAAgB,CAAmB;IAE3C,YAAY,gBAAkC;QAC5C,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAuB,EAAE,OAAe;QACpD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,IAAI,sBAAsB,CAAC;QAEvD,wCAAwC;QACxC,IAAI,IAAI,CAAC,gBAAgB,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;YACtD,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,cAAc,CAAC,yBAAyB,CAAC,UAAU,CAAC;qBAC3D;iBACF;aACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAEvD,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,uEAAuE,UAAU,yDAAyD;qBACjJ;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,gCAAgC,KAAK,CAAC,OAAO,EAAE;qBACtD;iBACF;aACF,CAAC;QACJ,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/dist/mcp/tools/index.d.ts b/dist/mcp/tools/index.d.ts new file mode 100644 index 0000000..5c512bd --- /dev/null +++ b/dist/mcp/tools/index.d.ts @@ -0,0 +1,7 @@ +/** + * MCP Tools + * Central export point for all tool handlers + */ +export { AnalyzeTool, type AnalyzeToolArgs } from './analyze-tool.js'; +export { SaveResultsTool, type SaveResultsToolArgs } from './save-results-tool.js'; +export { DashboardTool, type DashboardToolArgs } from './dashboard-tool.js'; diff --git a/dist/mcp/tools/index.js b/dist/mcp/tools/index.js new file mode 100644 index 0000000..aea335d --- /dev/null +++ b/dist/mcp/tools/index.js @@ -0,0 +1,8 @@ +/** + * MCP Tools + * Central export point for all tool handlers + */ +export { AnalyzeTool } from './analyze-tool.js'; +export { SaveResultsTool } from './save-results-tool.js'; +export { DashboardTool } from './dashboard-tool.js'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/mcp/tools/index.js.map b/dist/mcp/tools/index.js.map new file mode 100644 index 0000000..edccf3e --- /dev/null +++ b/dist/mcp/tools/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/tools/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAwB,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,eAAe,EAA4B,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAAE,aAAa,EAA0B,MAAM,qBAAqB,CAAC"} \ No newline at end of file diff --git a/dist/mcp/tools/save-results-tool.d.ts b/dist/mcp/tools/save-results-tool.d.ts new file mode 100644 index 0000000..791d2da --- /dev/null +++ b/dist/mcp/tools/save-results-tool.d.ts @@ -0,0 +1,37 @@ +/** + * Save Analysis Results Tool Handler + * Handles the 'saveAnalysisResults' MCP tool + * Single Responsibility: Persist analysis results to database + */ +import type { McpToolResponse } from '../types.js'; +export interface SaveResultsToolArgs { + prNumber?: number; + title: string; + repoOwner?: string; + repoName?: string; + author?: string; + complexity: number; + risksCount: number; + risks: string[]; + recommendations: string[]; + projectClassification?: string; + peerReviewEnabled?: boolean; + ticketKey?: string; + ticketQualityScore?: number; + ticketQualityTier?: string; + acCompliancePercentage?: number; + acRequirementsMet?: number; + acRequirementsTotal?: number; + peerReviewVerdict?: string; + peerReviewBlockers?: string[]; + peerReviewWarnings?: string[]; + implementationCompleteness?: number; + qualityScore?: number; + devopsCostMonthly?: number; + devopsResources?: string; +} +export declare class SaveResultsTool { + private dashboardPort; + constructor(dashboardPort?: number); + execute(args: SaveResultsToolArgs): Promise; +} diff --git a/dist/mcp/tools/save-results-tool.js b/dist/mcp/tools/save-results-tool.js new file mode 100644 index 0000000..48cab66 --- /dev/null +++ b/dist/mcp/tools/save-results-tool.js @@ -0,0 +1,66 @@ +/** + * Save Analysis Results Tool Handler + * Handles the 'saveAnalysisResults' MCP tool + * Single Responsibility: Persist analysis results to database + */ +import { saveAnalysis } from '../../db/index.js'; +import { SUCCESS_MESSAGES, ERROR_MESSAGES, DEFAULT_DASHBOARD_PORT } from '../constants.js'; +export class SaveResultsTool { + dashboardPort; + constructor(dashboardPort = DEFAULT_DASHBOARD_PORT) { + this.dashboardPort = dashboardPort; + } + async execute(args) { + try { + saveAnalysis({ + pr_number: args.prNumber || Math.floor(Date.now() / 1000) % 100000, + repo_owner: args.repoOwner || 'local', + repo_name: args.repoName || 'unknown', + author: args.author || 'unknown', + title: args.title, + complexity: args.complexity, + risks_count: args.risksCount, + risks: JSON.stringify(args.risks), + recommendations: JSON.stringify(args.recommendations), + project_classification: args.projectClassification, + peer_review_enabled: args.peerReviewEnabled ? 1 : 0, + ticket_key: args.ticketKey, + ticket_quality_score: args.ticketQualityScore, + ticket_quality_tier: args.ticketQualityTier, + ac_compliance_percentage: args.acCompliancePercentage, + ac_requirements_met: args.acRequirementsMet, + ac_requirements_total: args.acRequirementsTotal, + peer_review_verdict: args.peerReviewVerdict, + peer_review_blockers: args.peerReviewBlockers + ? JSON.stringify(args.peerReviewBlockers) + : undefined, + peer_review_warnings: args.peerReviewWarnings + ? JSON.stringify(args.peerReviewWarnings) + : undefined, + implementation_completeness: args.implementationCompleteness, + quality_score: args.qualityScore, + devops_cost_monthly: args.devopsCostMonthly, + devops_resources: args.devopsResources, + }); + return { + content: [ + { + type: 'text', + text: SUCCESS_MESSAGES.ANALYSIS_SAVED(this.dashboardPort), + }, + ], + }; + } + catch (error) { + return { + content: [ + { + type: 'text', + text: ERROR_MESSAGES.SAVE_FAILED(error.message), + }, + ], + }; + } + } +} +//# sourceMappingURL=save-results-tool.js.map \ No newline at end of file diff --git a/dist/mcp/tools/save-results-tool.js.map b/dist/mcp/tools/save-results-tool.js.map new file mode 100644 index 0000000..5c445a0 --- /dev/null +++ b/dist/mcp/tools/save-results-tool.js.map @@ -0,0 +1 @@ +{"version":3,"file":"save-results-tool.js","sourceRoot":"","sources":["../../../src/mcp/tools/save-results-tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AA6B3F,MAAM,OAAO,eAAe;IAClB,aAAa,CAAS;IAE9B,YAAY,gBAAwB,sBAAsB;QACxD,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAyB;QACrC,IAAI,CAAC;YACH,YAAY,CAAC;gBACX,SAAS,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM;gBAClE,UAAU,EAAE,IAAI,CAAC,SAAS,IAAI,OAAO;gBACrC,SAAS,EAAE,IAAI,CAAC,QAAQ,IAAI,SAAS;gBACrC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,SAAS;gBAChC,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,WAAW,EAAE,IAAI,CAAC,UAAU;gBAC5B,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;gBACjC,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC;gBACrD,sBAAsB,EAAE,IAAI,CAAC,qBAAqB;gBAClD,mBAAmB,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnD,UAAU,EAAE,IAAI,CAAC,SAAS;gBAC1B,oBAAoB,EAAE,IAAI,CAAC,kBAAkB;gBAC7C,mBAAmB,EAAE,IAAI,CAAC,iBAAiB;gBAC3C,wBAAwB,EAAE,IAAI,CAAC,sBAAsB;gBACrD,mBAAmB,EAAE,IAAI,CAAC,iBAAiB;gBAC3C,qBAAqB,EAAE,IAAI,CAAC,mBAAmB;gBAC/C,mBAAmB,EAAE,IAAI,CAAC,iBAAiB;gBAC3C,oBAAoB,EAAE,IAAI,CAAC,kBAAkB;oBAC3C,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC;oBACzC,CAAC,CAAC,SAAS;gBACb,oBAAoB,EAAE,IAAI,CAAC,kBAAkB;oBAC3C,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC;oBACzC,CAAC,CAAC,SAAS;gBACb,2BAA2B,EAAE,IAAI,CAAC,0BAA0B;gBAC5D,aAAa,EAAE,IAAI,CAAC,YAAY;gBAChC,mBAAmB,EAAE,IAAI,CAAC,iBAAiB;gBAC3C,gBAAgB,EAAE,IAAI,CAAC,eAAe;aACvC,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,gBAAgB,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC;qBAC1D;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,cAAc,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC;qBAChD;iBACF;aACF,CAAC;QACJ,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/dist/mcp/types.d.ts b/dist/mcp/types.d.ts new file mode 100644 index 0000000..5b2df39 --- /dev/null +++ b/dist/mcp/types.d.ts @@ -0,0 +1,100 @@ +/** + * MCP Server Types + * Type definitions specific to the MCP server implementation + */ +import type { AnalysisPrompt } from '../types/agent.types.js'; +/** + * Repository information extracted from git remote + */ +export interface RepoInfo { + owner: string; + name: string; +} +/** + * Git diff file metadata + */ +export interface DiffFileMetadata { + path: string; + additions: number; + deletions: number; + status: 'added' | 'deleted' | 'modified'; +} +/** + * Ticket reference extracted from PR metadata + */ +export interface TicketReference { + key: string; + source: 'title' | 'branch' | 'commit' | 'description'; + confidence: number; +} +/** + * Dashboard statistics + */ +export interface DashboardStats { + totalAnalyses: number; + averageComplexity: number; + criticalRisks: number; + recentActivity: Array<{ + date: string; + count: number; + }>; +} +/** + * MCP Tool Response format + * Matches the MCP SDK's expected return type with index signature + */ +export interface McpToolResponse { + [x: string]: unknown; + content: Array<{ + type: 'text'; + text: string; + }>; +} +/** + * Analysis output formatting options + */ +export interface AnalysisOutputOptions { + verbose: boolean; + peerReviewEnabled: boolean; + peerReviewError?: string; + allPrompts: AnalysisPrompt[]; + staticAnalysis?: any; + devOpsCostEstimates?: Array<{ + resource: string; + resourceType: string; + estimatedNewCost: number; + confidence: 'high' | 'medium' | 'low'; + details?: string; + }>; + totalDevOpsCost?: number; + projectClassification?: any; + repoInfo: RepoInfo; + currentBranch: string; + baseBranch?: string; + title?: string; +} +/** + * Dashboard server state + */ +export interface DashboardServerState { + httpServer: any | null; + port: number | null; +} +/** + * Git operation options + */ +export interface GitOperationOptions { + cwd?: string; + maxBuffer?: number; +} +/** + * Peer review analysis context + */ +export interface PeerReviewContext { + config: any; + diff: string; + title: string | undefined; + prAnalysisResult: any; + verbose: boolean; + workDir: string; +} diff --git a/dist/mcp/types.js b/dist/mcp/types.js new file mode 100644 index 0000000..2336db4 --- /dev/null +++ b/dist/mcp/types.js @@ -0,0 +1,6 @@ +/** + * MCP Server Types + * Type definitions specific to the MCP server implementation + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dist/src/types.js.map b/dist/mcp/types.js.map similarity index 53% rename from dist/src/types.js.map rename to dist/mcp/types.js.map index 7b5fff8..f57b3b9 100644 --- a/dist/src/types.js.map +++ b/dist/mcp/types.js.map @@ -1 +1 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""} \ No newline at end of file +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mcp/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"} \ No newline at end of file diff --git a/dist/package.json b/dist/package.json deleted file mode 100644 index 3dbc1ca..0000000 --- a/dist/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} diff --git a/dist/pr-agent-tools.d.ts b/dist/pr-agent-tools.d.ts deleted file mode 100644 index f69e320..0000000 --- a/dist/pr-agent-tools.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * LangChain Tools for PR Analysis Agent - * Main entry point - assembles all tools from separate modules - */ -import { DynamicStructuredTool } from '@langchain/core/tools'; -import type { ToolContext } from './tools/types'; -export type { ToolContext }; -/** - * Create all LangChain tools for the PR analysis agent - */ -export declare function createLangChainTools(context: ToolContext): DynamicStructuredTool[]; diff --git a/dist/pr-agent-tools.js b/dist/pr-agent-tools.js deleted file mode 100644 index a2deaa0..0000000 --- a/dist/pr-agent-tools.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict"; -/** - * LangChain Tools for PR Analysis Agent - * Main entry point - assembles all tools from separate modules - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createLangChainTools = createLangChainTools; -const analyze_file_group_1 = require("./tools/analyze-file-group"); -const check_imports_1 = require("./tools/check-imports"); -const synthesize_1 = require("./tools/synthesize"); -const state_tools_1 = require("./tools/state-tools"); -/** - * Create all LangChain tools for the PR analysis agent - */ -function createLangChainTools(context) { - const tools = []; - // Add individual tools - tools.push(createAnalyzeFileTool(context)); - tools.push((0, analyze_file_group_1.createAnalyzeFileGroupTool)(context)); - const checkImportsTool = (0, check_imports_1.createCheckImportsTool)(context); - if (checkImportsTool) { - tools.push(checkImportsTool); - } - tools.push((0, synthesize_1.createSynthesizeTool)(context)); - // Add state tools - tools.push(...(0, state_tools_1.createStateTools)(context)); - return tools; -} -//# sourceMappingURL=pr-agent-tools.js.map \ No newline at end of file diff --git a/dist/pr-agent-tools.js.map b/dist/pr-agent-tools.js.map deleted file mode 100644 index 092c2f1..0000000 --- a/dist/pr-agent-tools.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"pr-agent-tools.js","sourceRoot":"","sources":["../src/pr-agent-tools.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAcH,oDAkBC;AA7BD,mEAAwE;AACxE,yDAA+D;AAC/D,mDAA0D;AAC1D,qDAAuD;AAKvD;;GAEG;AACH,SAAgB,oBAAoB,CAAC,OAAoB;IACvD,MAAM,KAAK,GAA4B,EAAE,CAAC;IAE1C,uBAAuB;IACvB,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3C,KAAK,CAAC,IAAI,CAAC,IAAA,+CAA0B,EAAC,OAAO,CAAC,CAAC,CAAC;IAEhD,MAAM,gBAAgB,GAAG,IAAA,sCAAsB,EAAC,OAAO,CAAC,CAAC;IACzD,IAAI,gBAAgB,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAA,iCAAoB,EAAC,OAAO,CAAC,CAAC,CAAC;IAE1C,kBAAkB;IAClB,KAAK,CAAC,IAAI,CAAC,GAAG,IAAA,8BAAgB,EAAC,OAAO,CAAC,CAAC,CAAC;IAEzC,OAAO,KAAK,CAAC;AACf,CAAC"} \ No newline at end of file diff --git a/dist/prompts.d.ts b/dist/prompts.d.ts deleted file mode 100644 index a62f848..0000000 --- a/dist/prompts.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Prompt loader - loads prompt templates from files at runtime - * This avoids large string literals in TypeScript code, reducing compilation memory usage - */ -export declare function buildFileAnalysisPrompt(analysisContext: string, fileContent: string, filePath: string, fileStatus: string, isTerminal: boolean, mode: { - summary?: boolean; - risks?: boolean; - complexity?: boolean; -}): string; -export declare function buildSynthesisPrompt(synthesisContent: string, context: string[], analyzedFilesCount: number, isTerminal: boolean): string; diff --git a/dist/prompts.js b/dist/prompts.js deleted file mode 100644 index 77ad446..0000000 --- a/dist/prompts.js +++ /dev/null @@ -1,94 +0,0 @@ -"use strict"; -/** - * Prompt loader - loads prompt templates from files at runtime - * This avoids large string literals in TypeScript code, reducing compilation memory usage - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.buildFileAnalysisPrompt = buildFileAnalysisPrompt; -exports.buildSynthesisPrompt = buildSynthesisPrompt; -const fs_1 = require("fs"); -const path_1 = require("path"); -// Resolve prompts directory -// In compiled code: __dirname points to dist/, so prompts/ is at ../prompts -// Fallback: try relative to current working directory -const PROMPTS_DIR = (() => { - try { - // @ts-ignore - __dirname is available in CommonJS runtime - if (typeof __dirname !== 'undefined') { - return (0, path_1.join)(__dirname, '..', 'prompts'); - } - } - catch (e) { - // Fallback - } - // Fallback: relative to current working directory (for dev/testing) - return (0, path_1.join)(process.cwd(), 'prompts'); -})(); -// Cache for loaded prompts -const promptCache = new Map(); -function loadPrompt(filename) { - if (promptCache.has(filename)) { - return promptCache.get(filename); - } - try { - const content = (0, fs_1.readFileSync)((0, path_1.join)(PROMPTS_DIR, filename), 'utf-8'); - promptCache.set(filename, content); - return content; - } - catch (error) { - throw new Error(`Failed to load prompt file ${filename}: ${error.message}`); - } -} -function replacePlaceholders(template, replacements) { - let result = template; - for (const [key, value] of Object.entries(replacements)) { - result = result.replace(new RegExp(`{{${key}}}`, 'g'), value); - } - return result; -} -function buildFileAnalysisPrompt(analysisContext, fileContent, filePath, fileStatus, isTerminal, mode) { - const statusLabel = fileStatus === 'A' ? ' (NEW FILE)' : fileStatus === 'D' ? ' (DELETED)' : ''; - const contentLabel = fileStatus === 'A' - ? 'The following is the COMPLETE NEW FILE being added:' - : fileStatus === 'D' - ? 'The following shows the DELETED FILE and its removal:' - : 'The following is the diff of the PR that needs reviewing:'; - const formatSection = loadPrompt(isTerminal ? 'format-terminal.txt' : 'format-markdown.txt'); - const importantSection = loadPrompt(isTerminal ? 'important-terminal.txt' : 'important-markdown.txt'); - // Build sections dynamically - const sections = []; - if (mode.summary) { - sections.push(`\n\n${isTerminal ? 'Summary:' : '### Summary'}\n[Provide a brief summary of what the change does and its purpose]`); - } - if (mode.risks) { - sections.push(`\n\n${isTerminal ? 'Potential Risks:' : '### Potential Risks'}\n[ONLY list CRITICAL risks that would BREAK the build or cause runtime failures. Examples: missing imports that prevent compilation, type errors that block build, deleted exports used elsewhere, circular dependencies causing build failures. DO NOT include minor issues like unused imports, code style, or non-critical concerns. Format as: "- [File: path/to/file] Description (line X)" or write "None" if no critical risks]`); - } - if (mode.complexity) { - sections.push(`\n\n${isTerminal ? 'Complexity:' : '### Complexity'}\n[Rate as a number 1-5, where 1=trivial, 3=moderate, 5=very complex]`); - } - const template = loadPrompt('file-analysis.txt'); - return replacePlaceholders(template, { - analysisContext, - contentLabel, - fileContent, - filePath, - statusLabel, - outputFormat: isTerminal ? 'TERMINAL/CLI' : 'MARKDOWN', - formatSection: formatSection.trim(), - sections: sections.join(''), - importantSection: importantSection.trim() - }); -} -function buildSynthesisPrompt(synthesisContent, context, analyzedFilesCount, isTerminal) { - const instructions = loadPrompt(isTerminal ? 'synthesis-instructions-terminal.txt' : 'synthesis-instructions-markdown.txt'); - const importantSection = loadPrompt(isTerminal ? 'synthesis-important-terminal.txt' : 'synthesis-important-markdown.txt'); - const template = loadPrompt('synthesis.txt'); - return replacePlaceholders(template, { - analyzedFilesCount: analyzedFilesCount.toString(), - synthesisContent, - context: context.join('\n') || 'No additional context', - instructions: instructions.trim(), - importantSection: importantSection.trim() - }); -} -//# sourceMappingURL=prompts.js.map \ No newline at end of file diff --git a/dist/prompts.js.map b/dist/prompts.js.map deleted file mode 100644 index b8d048f..0000000 --- a/dist/prompts.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AA8CH,0DA0CC;AAED,oDAiBC;AAzGD,2BAAkC;AAClC,+BAA4B;AAE5B,4BAA4B;AAC5B,4EAA4E;AAC5E,sDAAsD;AACtD,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE;IACxB,IAAI,CAAC;QACH,0DAA0D;QAC1D,IAAI,OAAO,SAAS,KAAK,WAAW,EAAE,CAAC;YACrC,OAAO,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,WAAW;IACb,CAAC;IACD,oEAAoE;IACpE,OAAO,IAAA,WAAI,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;AACxC,CAAC,CAAC,EAAE,CAAC;AAEL,2BAA2B;AAC3B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE9C,SAAS,UAAU,CAAC,QAAgB;IAClC,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;IACpC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;QACnE,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnC,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAgB,EAAE,YAAoC;IACjF,IAAI,MAAM,GAAG,QAAQ,CAAC;IACtB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACxD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,uBAAuB,CACrC,eAAuB,EACvB,WAAmB,EACnB,QAAgB,EAChB,UAAkB,EAClB,UAAmB,EACnB,IAAkE;IAElE,MAAM,WAAW,GAAG,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAChG,MAAM,YAAY,GAAG,UAAU,KAAK,GAAG;QACrC,CAAC,CAAC,qDAAqD;QACvD,CAAC,CAAC,UAAU,KAAK,GAAG;YACpB,CAAC,CAAC,uDAAuD;YACzD,CAAC,CAAC,2DAA2D,CAAC;IAEhE,MAAM,aAAa,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;IAC7F,MAAM,gBAAgB,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC;IAEtG,6BAA6B;IAC7B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,qEAAqE,CAAC,CAAC;IACrI,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,qBAAqB,yaAAya,CAAC,CAAC;IACzf,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,uEAAuE,CAAC,CAAC;IAC7I,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC;IACjD,OAAO,mBAAmB,CAAC,QAAQ,EAAE;QACnC,eAAe;QACf,YAAY;QACZ,WAAW;QACX,QAAQ;QACR,WAAW;QACX,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU;QACtD,aAAa,EAAE,aAAa,CAAC,IAAI,EAAE;QACnC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,gBAAgB,EAAE,gBAAgB,CAAC,IAAI,EAAE;KAC1C,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,oBAAoB,CAClC,gBAAwB,EACxB,OAAiB,EACjB,kBAA0B,EAC1B,UAAmB;IAEnB,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC;IAC5H,MAAM,gBAAgB,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC;IAE1H,MAAM,QAAQ,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;IAC7C,OAAO,mBAAmB,CAAC,QAAQ,EAAE;QACnC,kBAAkB,EAAE,kBAAkB,CAAC,QAAQ,EAAE;QACjD,gBAAgB;QAChB,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,uBAAuB;QACtD,YAAY,EAAE,YAAY,CAAC,IAAI,EAAE;QACjC,gBAAgB,EAAE,gBAAgB,CAAC,IAAI,EAAE;KAC1C,CAAC,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/dist/providers/anthropic.provider.js b/dist/providers/anthropic.provider.js index d4fac9e..0c98d79 100644 --- a/dist/providers/anthropic.provider.js +++ b/dist/providers/anthropic.provider.js @@ -22,7 +22,8 @@ export class AnthropicProvider { apiKey: this.apiKey, modelName: config.model || this.getDefaultModel(), temperature: config.temperature ?? 0.2, - maxTokens: config.maxTokens ?? 4000, + maxTokens: config.maxTokens ?? 50000, + streaming: true, }); } } diff --git a/dist/providers/anthropic.provider.js.map b/dist/providers/anthropic.provider.js.map index 4aa0528..8423ead 100644 --- a/dist/providers/anthropic.provider.js.map +++ b/dist/providers/anthropic.provider.js.map @@ -1 +1 @@ -{"version":3,"file":"anthropic.provider.js","sourceRoot":"","sources":["../../src/providers/anthropic.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACZ,IAAI,GAAG,WAAW,CAAC;IAClB,MAAM,CAAS;IAEhC,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAC9D,CAAC;IAEM,YAAY;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAEM,eAAe;QACpB,OAAO,4BAA4B,CAAC;IACtC,CAAC;IAEM,YAAY,CAAC,SAAyB,EAAE;QAC7C,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,IAAI,aAAa,CAAC;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACjD,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,GAAG;YACtC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;SACpC,CAAC,CAAC;IACL,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"anthropic.provider.js","sourceRoot":"","sources":["../../src/providers/anthropic.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACZ,IAAI,GAAG,WAAW,CAAC;IAClB,MAAM,CAAS;IAEhC,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAC9D,CAAC;IAEM,YAAY;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAEM,eAAe;QACpB,OAAO,4BAA4B,CAAC;IACtC,CAAC;IAEM,YAAY,CAAC,SAAyB,EAAE;QAC7C,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,IAAI,aAAa,CAAC;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACjD,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,GAAG;YACtC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK;YACpC,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;IACL,CAAC;CACF"} \ No newline at end of file diff --git a/dist/providers/base.d.ts b/dist/providers/base.d.ts deleted file mode 100644 index 94bbded..0000000 --- a/dist/providers/base.d.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { AIProviderConfig, AnalysisRequest, AnalysisResponse, ModelInfo, ProviderCapabilities, AIProviderType } from './types'; -export declare abstract class BaseAIProvider { - protected config: AIProviderConfig; - protected apiKey: string; - private promptCache; - constructor(config: AIProviderConfig); - /** - * Get the provider type - */ - abstract getProviderType(): AIProviderType; - /** - * Analyze a pull request diff and return structured insights - */ - abstract analyze(request: AnalysisRequest): Promise; - /** - * Validate the provider configuration - */ - abstract validateConfig(): Promise; - /** - * Get information about the configured model - */ - abstract getModelInfo(): ModelInfo; - /** - * Get provider capabilities - */ - abstract getCapabilities(): ProviderCapabilities; - /** - * Get the API key from environment variables - * Each provider should override this to specify their env var name - */ - protected abstract getApiKeyFromEnv(): string; - /** - * Build the analysis prompt for this provider - * Can be overridden by providers to optimize for their specific format - */ - protected buildPrompt(request: AnalysisRequest): string; - /** - * Parse the AI response into structured format - * Can be overridden by providers if they need custom parsing - */ - protected parseResponse(response: string): Omit; - /** - * Handle provider-specific errors - */ - protected handleError(error: any): never; - /** - * Check if the diff is too large for the provider's context window - */ - protected isDiffTooLarge(diff: string): boolean; - /** - * Truncate diff if it's too large - */ - protected truncateDiff(diff: string): string; - /** - * Clear prompt cache (useful for testing) - */ - protected clearPromptCache(): void; - /** - * Get cache size (useful for monitoring) - */ - protected getPromptCacheSize(): number; -} diff --git a/dist/providers/base.js b/dist/providers/base.js deleted file mode 100644 index b376eda..0000000 --- a/dist/providers/base.js +++ /dev/null @@ -1,155 +0,0 @@ -"use strict"; -// Base AI Provider Interface -// Abstract base class that all AI providers must implement -Object.defineProperty(exports, "__esModule", { value: true }); -exports.BaseAIProvider = void 0; -const constants_1 = require("./constants"); -class BaseAIProvider { - config; - apiKey; - promptCache = new Map(); - constructor(config) { - this.config = config; - this.apiKey = config.apiKey || this.getApiKeyFromEnv(); - if (!this.apiKey) { - throw new Error(`API key is required for ${config.provider} provider`); - } - // Validate API key format (basic check) - if (this.apiKey.length < constants_1.PROVIDER_CONSTANTS.MIN_API_KEY_LENGTH) { - throw new Error(`Invalid API key format for ${config.provider} provider`); - } - } - /** - * Build the analysis prompt for this provider - * Can be overridden by providers to optimize for their specific format - */ - buildPrompt(request) { - // Input validation - if (!request.diff || request.diff.trim().length === 0) { - throw new Error('Diff is required and cannot be empty'); - } - if (request.diff.length > constants_1.PROVIDER_CONSTANTS.MAX_DIFF_SIZE_BYTES) { - throw new Error(`Diff is too large (>${constants_1.PROVIDER_CONSTANTS.MAX_DIFF_SIZE_BYTES / 1000000}MB)`); - } - const outputFormat = request.outputFormat || 'markdown'; - const isTerminal = outputFormat === 'terminal'; - return ` -[ROLE] You are an expert software engineer and code reviewer. Your task is to analyze a GitHub pull request (PR) and provide a clear, actionable summary for reviewers. - -[CONTEXT] -The following is the diff of the PR that needs reviewing: -${request.diff} -${request.title ? `PR Title: ${request.title}` : ''} -${request.repository ? `Repository: ${request.repository}` : ''} -${request.prNumber ? `PR Number: #${request.prNumber}` : ''} - -[TASK] Analyze the PR and provide a concise, structured response following the guidelines below. - -[OUTPUT FORMATTING] (${isTerminal ? 'TERMINAL/CLI' : 'MARKDOWN'}): -${isTerminal ? `- Format for terminal/CLI display with chalk-like formatting -- Use simple, clean text formatting (avoid complex markdown) -- Use emoji sparingly for visual clarity (🔴 🟡 ✅ ⚠️) -- Use plain text with minimal markdown (avoid code blocks where possible) -- Keep lines concise and readable in monospace terminals -- Use simple bullet points with dashes (-)` : `- Use proper Markdown format for GitHub comments, docs, etc. -- Use proper headers (## or ### for sections) -- Use code blocks with language tags (triple backticks followed by language name like typescript) -- Use inline code backticks (single backticks around names) for function/class/import names -- Use bold (double asterisks around text) for emphasis on important points -- Use bullet points (- or *) for lists -- Ensure proper markdown syntax for GitHub rendering`} - -[GUIDELINES] -1. Provide a **Summary**: briefly describe what the change does and its purpose. -2. Identify **Potential Risks**: list possible bugs, edge cases, or issues. Write "None" if no risks are apparent. - **CRITICAL**: Prioritize build-breaking issues at the top of the risks list: - - Missing imports (modules/functions/classes imported but not available) - - Unused imports that should be removed - - Type errors that would cause compilation failures - - Deleted exports that other files might depend on - - Renamed functions/classes that break existing usages - - Circular dependency issues - - Syntax errors - - Missing package.json dependencies for new imports - - Incorrect import paths (relative vs absolute) -3. Rate **Complexity (1–5)**: - - 1 = trivial (small, safe, no risk) - - 3 = moderate (requires some attention, medium risk) - - 5 = very complex (large change, high risk, needs deep review) -4. Keep the response under 250 words. -5. Focus on clarity and actionable insights relevant for reviewers. -6. Reference specific files, line numbers, or imports that are problematic. -7. Use Markdown for formatting. -8. Do not include generic introductions like "Let's analyze this PR". -9. Start directly with the analysis and be detailed. - `.trim(); - } - /** - * Parse the AI response into structured format - * Can be overridden by providers if they need custom parsing - */ - parseResponse(response) { - // Default parsing logic - extract summary, risks, and complexity - const summaryMatch = response.match(/\*\*Summary\*\*:?\s*(.*?)(?=\*\*|$)/is); - const risksMatch = response.match(/\*\*Potential Risks\*\*:?\s*(.*?)(?=\*\*|$)/is); - const complexityMatch = response.match(/\*\*Complexity.*?(\d+)/i); - const summary = summaryMatch?.[1]?.trim() || response.substring(0, 200); - // Parse risks - look for bullet points or numbered lists - const risksText = risksMatch?.[1]?.trim() || ''; - const risks = risksText.toLowerCase().includes('none') ? [] : - risksText.split(/\n\s*[-•*]\s+|\n\s*\d+\.\s+/) - .filter(risk => risk.trim().length > 0) - .map(risk => risk.trim().replace(/^[-•*]\s+|\d+\.\s+/, '')); - const complexity = complexityMatch ? parseInt(complexityMatch[1]) : 3; - return { - summary, - risks, - complexity: Math.max(1, Math.min(5, complexity)) // Ensure 1-5 range - }; - } - /** - * Handle provider-specific errors - */ - handleError(error) { - const providerError = new Error(`${this.getProviderType()} provider error: ${error.message}`); - providerError.provider = this.getProviderType(); - providerError.originalError = error; - throw providerError; - } - /** - * Check if the diff is too large for the provider's context window - */ - isDiffTooLarge(diff) { - const capabilities = this.getCapabilities(); - const estimatedTokens = Math.ceil(diff.length / constants_1.PROVIDER_CONSTANTS.CHARS_PER_TOKEN); - return estimatedTokens > (capabilities.maxContextLength * constants_1.PROVIDER_CONSTANTS.CONTEXT_USAGE_RATIO); - } - /** - * Truncate diff if it's too large - */ - truncateDiff(diff) { - const capabilities = this.getCapabilities(); - const maxChars = Math.floor(capabilities.maxContextLength * - constants_1.PROVIDER_CONSTANTS.CONTEXT_USAGE_RATIO * - constants_1.PROVIDER_CONSTANTS.CHARS_PER_TOKEN); - if (diff.length <= maxChars) { - return diff; - } - const truncated = diff.substring(0, maxChars); - return truncated + '\n\n[... diff truncated due to size limits ...]'; - } - /** - * Clear prompt cache (useful for testing) - */ - clearPromptCache() { - this.promptCache.clear(); - } - /** - * Get cache size (useful for monitoring) - */ - getPromptCacheSize() { - return this.promptCache.size; - } -} -exports.BaseAIProvider = BaseAIProvider; -//# sourceMappingURL=base.js.map \ No newline at end of file diff --git a/dist/providers/base.js.map b/dist/providers/base.js.map deleted file mode 100644 index e1707c9..0000000 --- a/dist/providers/base.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/providers/base.ts"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,2DAA2D;;;AAU3D,2CAAiD;AAEjD,MAAsB,cAAc;IACxB,MAAM,CAAmB;IACzB,MAAM,CAAS;IACjB,WAAW,GAAwB,IAAI,GAAG,EAAE,CAAC;IAErD,YAAY,MAAwB;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAEvD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,CAAC,QAAQ,WAAW,CAAC,CAAC;QACzE,CAAC;QAED,wCAAwC;QACxC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,8BAAkB,CAAC,kBAAkB,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,CAAC,QAAQ,WAAW,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAiCD;;;OAGG;IACO,WAAW,CAAC,OAAwB;QAC5C,mBAAmB;QACnB,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,8BAAkB,CAAC,mBAAmB,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,uBAAuB,8BAAkB,CAAC,mBAAmB,GAAG,OAAO,KAAK,CAAC,CAAC;QAChG,CAAC;QAED,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,UAAU,CAAC;QACxD,MAAM,UAAU,GAAG,YAAY,KAAK,UAAU,CAAC;QAE/C,OAAO;;;;;EAKT,OAAO,CAAC,IAAI;EACZ,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE;EACjD,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,eAAe,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE;EAC7D,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE;;;;uBAIpC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU;EAC7D,UAAU,CAAC,CAAC,CAAC;;;;;2CAK4B,CAAC,CAAC,CAAC;;;;;;qDAMO;;;;;;;;;;;;;;;;;;;;;;;;;KAyBhD,CAAC,IAAI,EAAE,CAAC;IACX,CAAC;IAED;;;OAGG;IACO,aAAa,CAAC,QAAgB;QACtC,iEAAiE;QACjE,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC7E,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnF,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAElE,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAExE,yDAAyD;QACzD,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3D,SAAS,CAAC,KAAK,CAAC,6BAA6B,CAAC;iBAC3C,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;iBACtC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC,CAAC;QAEhE,MAAM,UAAU,GAAG,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtE,OAAO;YACL,OAAO;YACP,KAAK;YACL,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,mBAAmB;SACrE,CAAC;IACJ,CAAC;IAED;;OAEG;IACO,WAAW,CAAC,KAAU;QAC9B,MAAM,aAAa,GAAG,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,eAAe,EAAE,oBAAoB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7F,aAAqB,CAAC,QAAQ,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACxD,aAAqB,CAAC,aAAa,GAAG,KAAK,CAAC;QAC7C,MAAM,aAAa,CAAC;IACtB,CAAC;IAED;;OAEG;IACO,cAAc,CAAC,IAAY;QACnC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,8BAAkB,CAAC,eAAe,CAAC,CAAC;QACpF,OAAO,eAAe,GAAG,CAAC,YAAY,CAAC,gBAAgB,GAAG,8BAAkB,CAAC,mBAAmB,CAAC,CAAC;IACpG,CAAC;IAED;;OAEG;IACO,YAAY,CAAC,IAAY;QACjC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CACzB,YAAY,CAAC,gBAAgB;YAC7B,8BAAkB,CAAC,mBAAmB;YACtC,8BAAkB,CAAC,eAAe,CACnC,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9C,OAAO,SAAS,GAAG,iDAAiD,CAAC;IACvE,CAAC;IAED;;OAEG;IACO,gBAAgB;QACxB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACO,kBAAkB;QAC1B,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;CACF;AAtMD,wCAsMC"} \ No newline at end of file diff --git a/dist/providers/claude.d.ts b/dist/providers/claude.d.ts deleted file mode 100644 index d2223a7..0000000 --- a/dist/providers/claude.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { BaseAIProvider } from './base'; -import { AIProviderConfig, AnalysisRequest, AnalysisResponse, ModelInfo, ProviderCapabilities, AIProviderType } from './types'; -export declare class ClaudeProvider extends BaseAIProvider { - private anthropic; - constructor(config: AIProviderConfig); - getProviderType(): AIProviderType; - protected getApiKeyFromEnv(): string; - analyze(request: AnalysisRequest): Promise; - validateConfig(): Promise; - getModelInfo(): ModelInfo; - getCapabilities(): ProviderCapabilities; - /** - * Claude-optimized prompt building - * Uses base class method which handles outputFormat - */ - protected buildPrompt(request: AnalysisRequest): string; -} diff --git a/dist/providers/claude.js b/dist/providers/claude.js deleted file mode 100644 index c50f9c5..0000000 --- a/dist/providers/claude.js +++ /dev/null @@ -1,213 +0,0 @@ -"use strict"; -// Claude AI Provider Implementation -// Anthropic Claude integration for PR analysis -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ClaudeProvider = void 0; -const sdk_1 = __importDefault(require("@anthropic-ai/sdk")); -const base_1 = require("./base"); -class ClaudeProvider extends base_1.BaseAIProvider { - anthropic; - constructor(config) { - super(config); - this.anthropic = new sdk_1.default({ - apiKey: this.apiKey - }); - } - getProviderType() { - return 'claude'; - } - getApiKeyFromEnv() { - return process.env.ANTHROPIC_API_KEY || ''; - } - async analyze(request) { - try { - // Validate request - if (!request || !request.diff) { - throw new Error('Invalid analysis request: diff is required'); - } - // Check if diff is too large (use copy to avoid mutation) - let processedDiff = request.diff; - if (this.isDiffTooLarge(processedDiff)) { - console.warn('Diff is too large, truncating...'); - processedDiff = this.truncateDiff(processedDiff); - } - const analysisRequest = { ...request, diff: processedDiff }; - const prompt = this.buildPrompt(analysisRequest); - const response = await this.anthropic.messages.create({ - model: this.config.model, - max_tokens: this.config.maxTokens, - temperature: this.config.temperature, - messages: [{ role: 'user', content: prompt }] - }); - const text = response.content - .filter((block) => block.type === 'text') - .map(block => block.text) - .join(''); - if (!text) { - throw new Error('Empty response from Claude'); - } - const parsed = this.parseResponse(text); - return { - ...parsed, - provider: this.getProviderType(), - model: this.config.model, - tokensUsed: response.usage?.input_tokens ? - response.usage.input_tokens + (response.usage.output_tokens || 0) : - undefined - }; - } - catch (error) { - console.error(`Claude provider error:`, { - status: error.status, - message: error.message, - model: this.config.model - }); - // Handle Claude-specific errors - if (error.status === 429) { - const rateLimitError = new Error(`Claude rate limit exceeded: ${error.message}`); - rateLimitError.provider = this.getProviderType(); - rateLimitError.retryable = true; - rateLimitError.rateLimited = true; - rateLimitError.retryAfter = error.headers?.['retry-after']; - throw rateLimitError; - } - if (error.status === 401) { - const authError = new Error(`Claude authentication failed: Invalid API key`); - authError.provider = this.getProviderType(); - authError.retryable = false; - throw authError; - } - if (error.status >= 500) { - const serverError = new Error(`Claude server error: ${error.message}`); - serverError.provider = this.getProviderType(); - serverError.retryable = true; - throw serverError; - } - this.handleError(error); - } - } - async validateConfig() { - try { - // Test with a minimal request - await this.anthropic.messages.create({ - model: this.config.model, - max_tokens: 10, - messages: [{ role: 'user', content: 'Hello' }] - }); - return true; - } - catch (error) { - console.error('Claude config validation failed:', error); - return false; - } - } - getModelInfo() { - const modelConfigs = { - 'claude-sonnet-4-5-20250929': { - name: 'Claude Sonnet 4.5', - maxTokens: 200000, - costPer1kTokens: { input: 0.003, output: 0.015 }, - capabilities: { - maxContextLength: 200000, - supportsImages: true, - supportsStreaming: true, - supportsFunctionCalling: true, - rateLimitRpm: 5000, - rateLimitTpm: 500000 - } - }, - 'claude-sonnet-4-20250514': { - name: 'Claude Sonnet 4', - maxTokens: 200000, - costPer1kTokens: { input: 0.003, output: 0.015 }, - capabilities: { - maxContextLength: 200000, - supportsImages: true, - supportsStreaming: true, - supportsFunctionCalling: true, - rateLimitRpm: 5000, - rateLimitTpm: 500000 - } - }, - 'claude-opus-4-20250514': { - name: 'Claude Opus 4', - maxTokens: 200000, - costPer1kTokens: { input: 0.015, output: 0.075 }, - capabilities: { - maxContextLength: 200000, - supportsImages: true, - supportsStreaming: true, - supportsFunctionCalling: true, - rateLimitRpm: 2000, - rateLimitTpm: 200000 - } - }, - // Legacy models kept for backward compatibility - 'claude-3-5-sonnet-20241022': { - name: 'Claude 3.5 Sonnet', - maxTokens: 200000, - costPer1kTokens: { input: 0.003, output: 0.015 }, - capabilities: { - maxContextLength: 200000, - supportsImages: true, - supportsStreaming: true, - supportsFunctionCalling: true, - rateLimitRpm: 4000, - rateLimitTpm: 400000 - } - }, - 'claude-3-sonnet-20240229': { - name: 'Claude 3 Sonnet', - maxTokens: 200000, - costPer1kTokens: { input: 0.003, output: 0.015 }, - capabilities: { - maxContextLength: 200000, - supportsImages: true, - supportsStreaming: true, - supportsFunctionCalling: true, - rateLimitRpm: 4000, - rateLimitTpm: 400000 - } - }, - 'claude-3-haiku-20240307': { - name: 'Claude 3 Haiku', - maxTokens: 200000, - costPer1kTokens: { input: 0.00025, output: 0.00125 }, - capabilities: { - maxContextLength: 200000, - supportsImages: true, - supportsStreaming: true, - supportsFunctionCalling: true, - rateLimitRpm: 4000, - rateLimitTpm: 400000 - } - } - }; - return modelConfigs[this.config.model] || { - name: this.config.model, - maxTokens: 200000, - capabilities: { - maxContextLength: 200000, - supportsImages: false, - supportsStreaming: true, - supportsFunctionCalling: false - } - }; - } - getCapabilities() { - return this.getModelInfo().capabilities; - } - /** - * Claude-optimized prompt building - * Uses base class method which handles outputFormat - */ - buildPrompt(request) { - // Use base class method which properly handles outputFormat - return super.buildPrompt(request); - } -} -exports.ClaudeProvider = ClaudeProvider; -//# sourceMappingURL=claude.js.map \ No newline at end of file diff --git a/dist/providers/claude.js.map b/dist/providers/claude.js.map deleted file mode 100644 index 7dff22b..0000000 --- a/dist/providers/claude.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/providers/claude.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/providers/constants.d.ts b/dist/providers/constants.d.ts deleted file mode 100644 index 6346a02..0000000 --- a/dist/providers/constants.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -export declare const PROVIDER_CONSTANTS: { - readonly CHARS_PER_TOKEN: 4; - readonly CONTEXT_USAGE_RATIO: 0.8; - readonly MAX_DIFF_SIZE_BYTES: 1000000; - readonly MIN_API_KEY_LENGTH: 10; - readonly MAX_VALIDATION_TOKENS: 10; - readonly MIN_DIFF_LENGTH: 1; - readonly DEFAULT_TIMEOUT: 30000; - readonly VALIDATION_TIMEOUT: 10000; - readonly MAX_RETRIES: 3; - readonly RETRY_DELAY_MS: 1000; - readonly EXPONENTIAL_BACKOFF_FACTOR: 2; -}; -export declare const MODEL_DEFAULTS: { - readonly claude: { - readonly model: "claude-sonnet-4-5-20250929"; - readonly maxTokens: 1500; - readonly temperature: 0.2; - }; - readonly openai: { - readonly model: "gpt-4-turbo"; - readonly maxTokens: 1500; - readonly temperature: 0.2; - }; - readonly gemini: { - readonly model: "gemini-pro"; - readonly maxTokens: 1500; - readonly temperature: 0.2; - }; -}; diff --git a/dist/providers/constants.js b/dist/providers/constants.js deleted file mode 100644 index b59b5e0..0000000 --- a/dist/providers/constants.js +++ /dev/null @@ -1,42 +0,0 @@ -"use strict"; -// Provider Constants -// Centralized constants for AI providers -Object.defineProperty(exports, "__esModule", { value: true }); -exports.MODEL_DEFAULTS = exports.PROVIDER_CONSTANTS = void 0; -exports.PROVIDER_CONSTANTS = { - // Token estimation (rough approximation: 1 token ≈ 4 characters) - CHARS_PER_TOKEN: 4, - // Context window usage (use 80% to leave room for response) - CONTEXT_USAGE_RATIO: 0.8, - // Diff size limits - MAX_DIFF_SIZE_BYTES: 1000000, // 1MB - MIN_API_KEY_LENGTH: 10, - // Validation limits - MAX_VALIDATION_TOKENS: 10, - MIN_DIFF_LENGTH: 1, - // Default timeouts (in milliseconds) - DEFAULT_TIMEOUT: 30000, // 30 seconds - VALIDATION_TIMEOUT: 10000, // 10 seconds - // Retry configuration - MAX_RETRIES: 3, - RETRY_DELAY_MS: 1000, - EXPONENTIAL_BACKOFF_FACTOR: 2 -}; -exports.MODEL_DEFAULTS = { - claude: { - model: 'claude-sonnet-4-5-20250929', - maxTokens: 1500, - temperature: 0.2 - }, - openai: { - model: 'gpt-4-turbo', - maxTokens: 1500, - temperature: 0.2 - }, - gemini: { - model: 'gemini-pro', - maxTokens: 1500, - temperature: 0.2 - } -}; -//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/providers/constants.js.map b/dist/providers/constants.js.map deleted file mode 100644 index ed2e519..0000000 --- a/dist/providers/constants.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/providers/constants.ts"],"names":[],"mappings":";AAAA,qBAAqB;AACrB,yCAAyC;;;AAE5B,QAAA,kBAAkB,GAAG;IAChC,iEAAiE;IACjE,eAAe,EAAE,CAAC;IAElB,4DAA4D;IAC5D,mBAAmB,EAAE,GAAG;IAExB,mBAAmB;IACnB,mBAAmB,EAAE,OAAO,EAAE,MAAM;IACpC,kBAAkB,EAAE,EAAE;IAEtB,oBAAoB;IACpB,qBAAqB,EAAE,EAAE;IACzB,eAAe,EAAE,CAAC;IAElB,qCAAqC;IACrC,eAAe,EAAE,KAAK,EAAE,aAAa;IACrC,kBAAkB,EAAE,KAAK,EAAE,aAAa;IAExC,sBAAsB;IACtB,WAAW,EAAE,CAAC;IACd,cAAc,EAAE,IAAI;IACpB,0BAA0B,EAAE,CAAC;CACrB,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,MAAM,EAAE;QACN,KAAK,EAAE,4BAA4B;QACnC,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,GAAG;KACjB;IACD,MAAM,EAAE;QACN,KAAK,EAAE,aAAa;QACpB,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,GAAG;KACjB;IACD,MAAM,EAAE;QACN,KAAK,EAAE,YAAY;QACnB,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,GAAG;KACjB;CACO,CAAC"} \ No newline at end of file diff --git a/dist/providers/factory.d.ts b/dist/providers/factory.d.ts deleted file mode 100644 index c0779fc..0000000 --- a/dist/providers/factory.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { BaseAIProvider } from './base'; -import { AIProviderConfig, AIProviderType } from './types'; -import { PRAnalyzerConfig } from '../types'; -/** - * Register a provider class with the factory - */ -export declare function registerProvider(type: AIProviderType, providerClass: new (config: AIProviderConfig) => BaseAIProvider): void; -/** - * Create an AI provider instance based on configuration - */ -export declare function createProvider(config: AIProviderConfig): BaseAIProvider; -/** - * Create provider from PR analyzer configuration - */ -export declare function createProviderFromConfig(prConfig: PRAnalyzerConfig, providerType?: AIProviderType): BaseAIProvider; -/** - * Get list of available providers - */ -export declare function getAvailableProviders(): AIProviderType[]; -/** - * Check if a provider is available - */ -export declare function isProviderAvailable(provider: AIProviderType): boolean; -/** - * Validate provider configuration - */ -export declare function validateProviderConfig(config: AIProviderConfig): Promise; -/** - * Get default configuration for a provider type - */ -export declare function getDefaultConfig(providerType: AIProviderType): Partial; diff --git a/dist/providers/factory.js b/dist/providers/factory.js deleted file mode 100644 index 911f3c7..0000000 --- a/dist/providers/factory.js +++ /dev/null @@ -1,106 +0,0 @@ -"use strict"; -// AI Provider Factory -// Factory pattern for creating and managing AI providers -Object.defineProperty(exports, "__esModule", { value: true }); -exports.registerProvider = registerProvider; -exports.createProvider = createProvider; -exports.createProviderFromConfig = createProviderFromConfig; -exports.getAvailableProviders = getAvailableProviders; -exports.isProviderAvailable = isProviderAvailable; -exports.validateProviderConfig = validateProviderConfig; -exports.getDefaultConfig = getDefaultConfig; -const claude_1 = require("./claude"); -const constants_1 = require("./constants"); -// Provider registry - will be populated as providers are implemented -const PROVIDER_REGISTRY = new Map(); -// Register available providers -registerProvider('claude', claude_1.ClaudeProvider); -/** - * Register a provider class with the factory - */ -function registerProvider(type, providerClass) { - PROVIDER_REGISTRY.set(type, providerClass); -} -/** - * Create an AI provider instance based on configuration - */ -function createProvider(config) { - // Validate configuration - if (!config) { - throw new Error('Provider configuration is required'); - } - if (!config.provider) { - throw new Error('Provider type is required in configuration'); - } - if (!config.model) { - throw new Error('Model is required in provider configuration'); - } - if (typeof config.maxTokens !== 'number' || config.maxTokens <= 0) { - throw new Error('maxTokens must be a positive number'); - } - if (typeof config.temperature !== 'number' || config.temperature < 0 || config.temperature > 2) { - throw new Error('temperature must be a number between 0 and 2'); - } - const ProviderClass = PROVIDER_REGISTRY.get(config.provider); - if (!ProviderClass) { - const availableProviders = Array.from(PROVIDER_REGISTRY.keys()).join(', '); - console.error(`Failed to create provider: '${config.provider}' not found. Available: ${availableProviders}`); - throw new Error(`Provider '${config.provider}' is not registered. Available providers: ${availableProviders}`); - } - console.info(`Creating ${config.provider} provider with model: ${config.model}`); - return new ProviderClass(config); -} -/** - * Create provider from PR analyzer configuration - */ -function createProviderFromConfig(prConfig, providerType) { - const targetProvider = providerType || prConfig.ai.provider; - const providerConfig = prConfig.ai.providers[targetProvider]; - if (!providerConfig) { - throw new Error(`No configuration found for provider '${targetProvider}'`); - } - const aiProviderConfig = { - provider: targetProvider, - model: providerConfig.model, - maxTokens: providerConfig.maxTokens, - temperature: providerConfig.temperature, - baseUrl: providerConfig.baseUrl, - timeout: providerConfig.timeout - }; - return createProvider(aiProviderConfig); -} -/** - * Get list of available providers - */ -function getAvailableProviders() { - return Array.from(PROVIDER_REGISTRY.keys()); -} -/** - * Check if a provider is available - */ -function isProviderAvailable(provider) { - return PROVIDER_REGISTRY.has(provider); -} -/** - * Validate provider configuration - */ -async function validateProviderConfig(config) { - try { - const provider = createProvider(config); - return await provider.validateConfig(); - } - catch (error) { - console.error(`Provider validation failed for ${config.provider}:`, error); - return false; - } -} -/** - * Get default configuration for a provider type - */ -function getDefaultConfig(providerType) { - return { - provider: providerType, - ...constants_1.MODEL_DEFAULTS[providerType] - }; -} -//# sourceMappingURL=factory.js.map \ No newline at end of file diff --git a/dist/providers/factory.js.map b/dist/providers/factory.js.map deleted file mode 100644 index a8d6254..0000000 --- a/dist/providers/factory.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/providers/factory.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/providers/google.provider.js b/dist/providers/google.provider.js index 600320b..908d0b6 100644 --- a/dist/providers/google.provider.js +++ b/dist/providers/google.provider.js @@ -22,7 +22,7 @@ export class GoogleProvider { apiKey: this.apiKey, model: config.model || this.getDefaultModel(), temperature: config.temperature ?? 0.2, - maxOutputTokens: config.maxTokens ?? 4000, + maxOutputTokens: config.maxTokens ?? 50000, }); } } diff --git a/dist/providers/google.provider.js.map b/dist/providers/google.provider.js.map index b7685f9..3cdc3bc 100644 --- a/dist/providers/google.provider.js.map +++ b/dist/providers/google.provider.js.map @@ -1 +1 @@ -{"version":3,"file":"google.provider.js","sourceRoot":"","sources":["../../src/providers/google.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAIjE;;GAEG;AACH,MAAM,OAAO,cAAc;IACT,IAAI,GAAG,QAAQ,CAAC;IACf,MAAM,CAAS;IAEhC,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;IAC3D,CAAC;IAEM,YAAY;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAEM,eAAe;QACpB,OAAO,YAAY,CAAC;IACtB,CAAC;IAEM,YAAY,CAAC,SAAyB,EAAE;QAC7C,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,IAAI,sBAAsB,CAAC;YAChC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YAC7C,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,GAAG;YACtC,eAAe,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;SAC1C,CAAC,CAAC;IACL,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"google.provider.js","sourceRoot":"","sources":["../../src/providers/google.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAIjE;;GAEG;AACH,MAAM,OAAO,cAAc;IACT,IAAI,GAAG,QAAQ,CAAC;IACf,MAAM,CAAS;IAEhC,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;IAC3D,CAAC;IAEM,YAAY;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAEM,eAAe;QACpB,OAAO,YAAY,CAAC;IACtB,CAAC;IAEM,YAAY,CAAC,SAAyB,EAAE;QAC7C,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,IAAI,sBAAsB,CAAC;YAChC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YAC7C,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,GAAG;YACtC,eAAe,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK;SAC3C,CAAC,CAAC;IACL,CAAC;CACF"} \ No newline at end of file diff --git a/dist/providers/index.d.ts b/dist/providers/index.d.ts index 197c43e..abcb958 100644 --- a/dist/providers/index.d.ts +++ b/dist/providers/index.d.ts @@ -3,3 +3,4 @@ export * from './provider.factory.js'; export * from './anthropic.provider.js'; export * from './openai.provider.js'; export * from './google.provider.js'; +export * from './zhipu.provider.js'; diff --git a/dist/providers/index.js b/dist/providers/index.js index 11dbd8e..3d54524 100644 --- a/dist/providers/index.js +++ b/dist/providers/index.js @@ -3,4 +3,5 @@ export * from './provider.factory.js'; export * from './anthropic.provider.js'; export * from './openai.provider.js'; export * from './google.provider.js'; +export * from './zhipu.provider.js'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/providers/index.js.map b/dist/providers/index.js.map index 7e81376..8a72121 100644 --- a/dist/providers/index.js.map +++ b/dist/providers/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC"} \ No newline at end of file diff --git a/dist/providers/openai.provider.js b/dist/providers/openai.provider.js index 42ca225..31533d7 100644 --- a/dist/providers/openai.provider.js +++ b/dist/providers/openai.provider.js @@ -22,7 +22,7 @@ export class OpenAIProvider { apiKey: this.apiKey, modelName: config.model || this.getDefaultModel(), temperature: config.temperature ?? 0.2, - maxTokens: config.maxTokens ?? 4000, + maxTokens: config.maxTokens ?? 50000, }); } } diff --git a/dist/providers/openai.provider.js.map b/dist/providers/openai.provider.js.map index 7b50a6c..7660a35 100644 --- a/dist/providers/openai.provider.js.map +++ b/dist/providers/openai.provider.js.map @@ -1 +1 @@ -{"version":3,"file":"openai.provider.js","sourceRoot":"","sources":["../../src/providers/openai.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C;;GAEG;AACH,MAAM,OAAO,cAAc;IACT,IAAI,GAAG,QAAQ,CAAC;IACf,MAAM,CAAS;IAEhC,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;IAC3D,CAAC;IAEM,YAAY;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAEM,eAAe;QACpB,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAEM,YAAY,CAAC,SAAyB,EAAE;QAC7C,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,IAAI,UAAU,CAAC;YACpB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACjD,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,GAAG;YACtC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;SACpC,CAAC,CAAC;IACL,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"openai.provider.js","sourceRoot":"","sources":["../../src/providers/openai.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C;;GAEG;AACH,MAAM,OAAO,cAAc;IACT,IAAI,GAAG,QAAQ,CAAC;IACf,MAAM,CAAS;IAEhC,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;IAC3D,CAAC;IAEM,YAAY;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAEM,eAAe;QACpB,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAEM,YAAY,CAAC,SAAyB,EAAE;QAC7C,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,IAAI,UAAU,CAAC;YACpB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACjD,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,GAAG;YACtC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK;SACrC,CAAC,CAAC;IACL,CAAC;CACF"} \ No newline at end of file diff --git a/dist/providers/provider.factory.d.ts b/dist/providers/provider.factory.d.ts index ca4916a..e38f90e 100644 --- a/dist/providers/provider.factory.d.ts +++ b/dist/providers/provider.factory.d.ts @@ -1,6 +1,6 @@ import { ILLMProvider } from './provider.interface.js'; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; -export type SupportedProvider = 'anthropic' | 'openai' | 'google'; +export type SupportedProvider = 'anthropic' | 'openai' | 'google' | 'zhipu'; export interface ProviderOptions { provider?: SupportedProvider; apiKey?: string; diff --git a/dist/providers/provider.factory.js b/dist/providers/provider.factory.js index dd2fde9..4d1a3da 100644 --- a/dist/providers/provider.factory.js +++ b/dist/providers/provider.factory.js @@ -1,6 +1,7 @@ import { AnthropicProvider } from './anthropic.provider.js'; import { OpenAIProvider } from './openai.provider.js'; import { GoogleProvider } from './google.provider.js'; +import { ZhipuProvider } from './zhipu.provider.js'; /** * Factory for creating LLM providers */ @@ -28,8 +29,11 @@ export class ProviderFactory { case 'google': provider = new GoogleProvider(apiKey); break; + case 'zhipu': + provider = new ZhipuProvider(apiKey); + break; default: - throw new Error(`Unsupported provider: ${providerName}. Supported: anthropic, openai, google`); + throw new Error(`Unsupported provider: ${providerName}. Supported: anthropic, openai, google, zhipu`); } // Cache the provider if no specific API key was provided if (!apiKey) { @@ -81,13 +85,15 @@ export class ProviderFactory { return 'anthropic'; if (normalized === 'gemini') return 'google'; + if (normalized === 'glm' || normalized === 'zhipuai') + return 'zhipu'; return normalized; } /** * Get list of available providers */ static getAvailableProviders() { - return ['anthropic', 'openai', 'google']; + return ['anthropic', 'openai', 'google', 'zhipu']; } } //# sourceMappingURL=provider.factory.js.map \ No newline at end of file diff --git a/dist/providers/provider.factory.js.map b/dist/providers/provider.factory.js.map index 2926111..5bc47b1 100644 --- a/dist/providers/provider.factory.js.map +++ b/dist/providers/provider.factory.js.map @@ -1 +1 @@ -{"version":3,"file":"provider.factory.js","sourceRoot":"","sources":["../../src/providers/provider.factory.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"provider.factory.js","sourceRoot":"","sources":["../../src/providers/provider.factory.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/providers/types.d.ts b/dist/providers/types.d.ts deleted file mode 100644 index 39c44c5..0000000 --- a/dist/providers/types.d.ts +++ /dev/null @@ -1,54 +0,0 @@ -export type AIProviderType = 'claude' | 'openai' | 'gemini'; -export interface AIProviderConfig { - provider: AIProviderType; - model: string; - maxTokens: number; - temperature: number; - apiKey?: string; - baseUrl?: string; - timeout?: number; -} -export interface AnalysisRequest { - diff: string; - title?: string; - files?: string[]; - repository?: string; - prNumber?: number; - outputFormat?: 'terminal' | 'markdown'; -} -export interface AnalysisResponse { - summary: string; - risks: string[]; - complexity: number; - recommendations?: string[]; - provider: AIProviderType; - model: string; - tokensUsed?: number; -} -export interface ProviderCapabilities { - maxContextLength: number; - supportsImages: boolean; - supportsStreaming: boolean; - supportsFunctionCalling: boolean; - rateLimitRpm?: number; - rateLimitTpm?: number; -} -export interface ProviderError extends Error { - provider: AIProviderType; - code?: string; - statusCode?: number; - retryable: boolean; - rateLimited?: boolean; -} -export interface ModelInfo { - name: string; - maxTokens: number; - costPer1kTokens?: { - input: number; - output: number; - }; - capabilities: ProviderCapabilities; -} -export declare function isValidProviderType(value: any): value is AIProviderType; -export declare function isAnalysisResponse(value: any): value is AnalysisResponse; -export declare function isProviderError(error: any): error is ProviderError; diff --git a/dist/providers/types.js b/dist/providers/types.js deleted file mode 100644 index 3733acf..0000000 --- a/dist/providers/types.js +++ /dev/null @@ -1,31 +0,0 @@ -"use strict"; -// AI Provider Types -// Common types and interfaces for multi-provider support -Object.defineProperty(exports, "__esModule", { value: true }); -exports.isValidProviderType = isValidProviderType; -exports.isAnalysisResponse = isAnalysisResponse; -exports.isProviderError = isProviderError; -// Type guards for runtime type checking -function isValidProviderType(value) { - return ['claude', 'openai', 'gemini'].includes(value); -} -function isAnalysisResponse(value) { - if (!value || typeof value !== 'object') { - return false; - } - return (typeof value.summary === 'string' && - Array.isArray(value.risks) && - typeof value.complexity === 'number' && - isValidProviderType(value.provider) && - typeof value.model === 'string'); -} -function isProviderError(error) { - if (!error || !(error instanceof Error)) { - return false; - } - return ('provider' in error && - isValidProviderType(error.provider) && - 'retryable' in error && - typeof error.retryable === 'boolean'); -} -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dist/providers/types.js.map b/dist/providers/types.js.map deleted file mode 100644 index a1afd53..0000000 --- a/dist/providers/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB,yDAAyD;;AA6DzD,kDAEC;AAED,gDAYC;AAED,0CAWC;AA9BD,wCAAwC;AACxC,SAAgB,mBAAmB,CAAC,KAAU;IAC5C,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,SAAgB,kBAAkB,CAAC,KAAU;IAC3C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CACL,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;QACjC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;QAC1B,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ;QACpC,mBAAmB,CAAC,KAAK,CAAC,QAAQ,CAAC;QACnC,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAChC,CAAC;AACJ,CAAC;AAED,SAAgB,eAAe,CAAC,KAAU;IACxC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CACL,UAAU,IAAI,KAAK;QACnB,mBAAmB,CAAE,KAAa,CAAC,QAAQ,CAAC;QAC5C,WAAW,IAAI,KAAK;QACpB,OAAQ,KAAa,CAAC,SAAS,KAAK,SAAS,CAC9C,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/dist/providers/zhipu.provider.d.ts b/dist/providers/zhipu.provider.d.ts new file mode 100644 index 0000000..d46c5af --- /dev/null +++ b/dist/providers/zhipu.provider.d.ts @@ -0,0 +1,16 @@ +import { BaseChatModel } from '@langchain/core/language_models/chat_models'; +import { ILLMProvider, ProviderConfig } from './provider.interface.js'; +/** + * Zhipu AI (智谱AI) provider implementation + * Uses Anthropic-compatible API endpoint + * Docs: https://docs.z.ai/ + */ +export declare class ZhipuProvider implements ILLMProvider { + readonly name = "zhipu"; + private readonly apiKey; + private readonly baseUrl; + constructor(apiKey?: string); + isConfigured(): boolean; + getDefaultModel(): string; + getChatModel(config?: ProviderConfig): BaseChatModel; +} diff --git a/dist/providers/zhipu.provider.js b/dist/providers/zhipu.provider.js new file mode 100644 index 0000000..764c793 --- /dev/null +++ b/dist/providers/zhipu.provider.js @@ -0,0 +1,35 @@ +import { ChatAnthropic } from '@langchain/anthropic'; +/** + * Zhipu AI (智谱AI) provider implementation + * Uses Anthropic-compatible API endpoint + * Docs: https://docs.z.ai/ + */ +export class ZhipuProvider { + name = 'zhipu'; + apiKey; + baseUrl = 'https://api.z.ai/api/anthropic'; + constructor(apiKey) { + this.apiKey = apiKey || process.env.ZHIPU_API_KEY || ''; + } + isConfigured() { + return !!this.apiKey; + } + getDefaultModel() { + // GLM-4.7 via Z.AI's Anthropic-compatible API + return 'glm-4.7'; + } + getChatModel(config = {}) { + if (!this.isConfigured()) { + throw new Error('Zhipu API key is not configured. Set ZHIPU_API_KEY environment variable.'); + } + return new ChatAnthropic({ + anthropicApiKey: this.apiKey, + anthropicApiUrl: this.baseUrl, + modelName: config.model || this.getDefaultModel(), + temperature: config.temperature ?? 0.2, + maxTokens: config.maxTokens ?? 50000, + streaming: true, + }); + } +} +//# sourceMappingURL=zhipu.provider.js.map \ No newline at end of file diff --git a/dist/providers/zhipu.provider.js.map b/dist/providers/zhipu.provider.js.map new file mode 100644 index 0000000..a4973ed --- /dev/null +++ b/dist/providers/zhipu.provider.js.map @@ -0,0 +1 @@ +{"version":3,"file":"zhipu.provider.js","sourceRoot":"","sources":["../../src/providers/zhipu.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;GAIG;AACH,MAAM,OAAO,aAAa;IACR,IAAI,GAAG,OAAO,CAAC;IACd,MAAM,CAAS;IACf,OAAO,GAAG,gCAAgC,CAAC;IAE5D,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC;IAC1D,CAAC;IAEM,YAAY;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAEM,eAAe;QACpB,8CAA8C;QAC9C,OAAO,SAAS,CAAC;IACnB,CAAC;IAEM,YAAY,CAAC,SAAyB,EAAE;QAC7C,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;QAC9F,CAAC;QAED,OAAO,IAAI,aAAa,CAAC;YACvB,eAAe,EAAE,IAAI,CAAC,MAAM;YAC5B,eAAe,EAAE,IAAI,CAAC,OAAO;YAC7B,SAAS,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACjD,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,GAAG;YACtC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK;YACpC,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;IACL,CAAC;CACF"} \ No newline at end of file diff --git a/dist/sourcemap-register.cjs b/dist/sourcemap-register.cjs deleted file mode 100644 index cb1fb13..0000000 --- a/dist/sourcemap-register.cjs +++ /dev/null @@ -1 +0,0 @@ -(()=>{var e={296:e=>{var r=Object.prototype.toString;var n=typeof Buffer!=="undefined"&&typeof Buffer.alloc==="function"&&typeof Buffer.allocUnsafe==="function"&&typeof Buffer.from==="function";function isArrayBuffer(e){return r.call(e).slice(8,-1)==="ArrayBuffer"}function fromArrayBuffer(e,r,t){r>>>=0;var o=e.byteLength-r;if(o<0){throw new RangeError("'offset' is out of bounds")}if(t===undefined){t=o}else{t>>>=0;if(t>o){throw new RangeError("'length' is out of bounds")}}return n?Buffer.from(e.slice(r,r+t)):new Buffer(new Uint8Array(e.slice(r,r+t)))}function fromString(e,r){if(typeof r!=="string"||r===""){r="utf8"}if(!Buffer.isEncoding(r)){throw new TypeError('"encoding" must be a valid string encoding')}return n?Buffer.from(e,r):new Buffer(e,r)}function bufferFrom(e,r,t){if(typeof e==="number"){throw new TypeError('"value" argument must not be a number')}if(isArrayBuffer(e)){return fromArrayBuffer(e,r,t)}if(typeof e==="string"){return fromString(e,r)}return n?Buffer.from(e):new Buffer(e)}e.exports=bufferFrom},599:(e,r,n)=>{e=n.nmd(e);var t=n(927).SourceMapConsumer;var o=n(928);var i;try{i=n(896);if(!i.existsSync||!i.readFileSync){i=null}}catch(e){}var a=n(296);function dynamicRequire(e,r){return e.require(r)}var u=false;var s=false;var l=false;var c="auto";var p={};var f={};var g=/^data:application\/json[^,]+base64,/;var d=[];var h=[];function isInBrowser(){if(c==="browser")return true;if(c==="node")return false;return typeof window!=="undefined"&&typeof XMLHttpRequest==="function"&&!(window.require&&window.module&&window.process&&window.process.type==="renderer")}function hasGlobalProcessEventEmitter(){return typeof process==="object"&&process!==null&&typeof process.on==="function"}function globalProcessVersion(){if(typeof process==="object"&&process!==null){return process.version}else{return""}}function globalProcessStderr(){if(typeof process==="object"&&process!==null){return process.stderr}}function globalProcessExit(e){if(typeof process==="object"&&process!==null&&typeof process.exit==="function"){return process.exit(e)}}function handlerExec(e){return function(r){for(var n=0;n"}var n=this.getLineNumber();if(n!=null){r+=":"+n;var t=this.getColumnNumber();if(t){r+=":"+t}}}var o="";var i=this.getFunctionName();var a=true;var u=this.isConstructor();var s=!(this.isToplevel()||u);if(s){var l=this.getTypeName();if(l==="[object Object]"){l="null"}var c=this.getMethodName();if(i){if(l&&i.indexOf(l)!=0){o+=l+"."}o+=i;if(c&&i.indexOf("."+c)!=i.length-c.length-1){o+=" [as "+c+"]"}}else{o+=l+"."+(c||"")}}else if(u){o+="new "+(i||"")}else if(i){o+=i}else{o+=r;a=false}if(a){o+=" ("+r+")"}return o}function cloneCallSite(e){var r={};Object.getOwnPropertyNames(Object.getPrototypeOf(e)).forEach((function(n){r[n]=/^(?:is|get)/.test(n)?function(){return e[n].call(e)}:e[n]}));r.toString=CallSiteToString;return r}function wrapCallSite(e,r){if(r===undefined){r={nextPosition:null,curPosition:null}}if(e.isNative()){r.curPosition=null;return e}var n=e.getFileName()||e.getScriptNameOrSourceURL();if(n){var t=e.getLineNumber();var o=e.getColumnNumber()-1;var i=/^v(10\.1[6-9]|10\.[2-9][0-9]|10\.[0-9]{3,}|1[2-9]\d*|[2-9]\d|\d{3,}|11\.11)/;var a=i.test(globalProcessVersion())?0:62;if(t===1&&o>a&&!isInBrowser()&&!e.isEval()){o-=a}var u=mapSourcePosition({source:n,line:t,column:o});r.curPosition=u;e=cloneCallSite(e);var s=e.getFunctionName;e.getFunctionName=function(){if(r.nextPosition==null){return s()}return r.nextPosition.name||s()};e.getFileName=function(){return u.source};e.getLineNumber=function(){return u.line};e.getColumnNumber=function(){return u.column+1};e.getScriptNameOrSourceURL=function(){return u.source};return e}var l=e.isEval()&&e.getEvalOrigin();if(l){l=mapEvalOrigin(l);e=cloneCallSite(e);e.getEvalOrigin=function(){return l};return e}return e}function prepareStackTrace(e,r){if(l){p={};f={}}var n=e.name||"Error";var t=e.message||"";var o=n+": "+t;var i={nextPosition:null,curPosition:null};var a=[];for(var u=r.length-1;u>=0;u--){a.push("\n at "+wrapCallSite(r[u],i));i.nextPosition=i.curPosition}i.curPosition=i.nextPosition=null;return o+a.reverse().join("")}function getErrorSource(e){var r=/\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(e.stack);if(r){var n=r[1];var t=+r[2];var o=+r[3];var a=p[n];if(!a&&i&&i.existsSync(n)){try{a=i.readFileSync(n,"utf8")}catch(e){a=""}}if(a){var u=a.split(/(?:\r\n|\r|\n)/)[t-1];if(u){return n+":"+t+"\n"+u+"\n"+new Array(o).join(" ")+"^"}}}return null}function printErrorAndExit(e){var r=getErrorSource(e);var n=globalProcessStderr();if(n&&n._handle&&n._handle.setBlocking){n._handle.setBlocking(true)}if(r){console.error();console.error(r)}console.error(e.stack);globalProcessExit(1)}function shimEmitUncaughtException(){var e=process.emit;process.emit=function(r){if(r==="uncaughtException"){var n=arguments[1]&&arguments[1].stack;var t=this.listeners(r).length>0;if(n&&!t){return printErrorAndExit(arguments[1])}}return e.apply(this,arguments)}}var S=d.slice(0);var _=h.slice(0);r.wrapCallSite=wrapCallSite;r.getErrorSource=getErrorSource;r.mapSourcePosition=mapSourcePosition;r.retrieveSourceMap=v;r.install=function(r){r=r||{};if(r.environment){c=r.environment;if(["node","browser","auto"].indexOf(c)===-1){throw new Error("environment "+c+" was unknown. Available options are {auto, browser, node}")}}if(r.retrieveFile){if(r.overrideRetrieveFile){d.length=0}d.unshift(r.retrieveFile)}if(r.retrieveSourceMap){if(r.overrideRetrieveSourceMap){h.length=0}h.unshift(r.retrieveSourceMap)}if(r.hookRequire&&!isInBrowser()){var n=dynamicRequire(e,"module");var t=n.prototype._compile;if(!t.__sourceMapSupport){n.prototype._compile=function(e,r){p[r]=e;f[r]=undefined;return t.call(this,e,r)};n.prototype._compile.__sourceMapSupport=true}}if(!l){l="emptyCacheBetweenOperations"in r?r.emptyCacheBetweenOperations:false}if(!u){u=true;Error.prepareStackTrace=prepareStackTrace}if(!s){var o="handleUncaughtExceptions"in r?r.handleUncaughtExceptions:true;try{var i=dynamicRequire(e,"worker_threads");if(i.isMainThread===false){o=false}}catch(e){}if(o&&hasGlobalProcessEventEmitter()){s=true;shimEmitUncaughtException()}}};r.resetRetrieveHandlers=function(){d.length=0;h.length=0;d=S.slice(0);h=_.slice(0);v=handlerExec(h);m=handlerExec(d)}},517:(e,r,n)=>{var t=n(297);var o=Object.prototype.hasOwnProperty;var i=typeof Map!=="undefined";function ArraySet(){this._array=[];this._set=i?new Map:Object.create(null)}ArraySet.fromArray=function ArraySet_fromArray(e,r){var n=new ArraySet;for(var t=0,o=e.length;t=0){return r}}else{var n=t.toSetString(e);if(o.call(this._set,n)){return this._set[n]}}throw new Error('"'+e+'" is not in the set.')};ArraySet.prototype.at=function ArraySet_at(e){if(e>=0&&e{var t=n(158);var o=5;var i=1<>1;return r?-n:n}r.encode=function base64VLQ_encode(e){var r="";var n;var i=toVLQSigned(e);do{n=i&a;i>>>=o;if(i>0){n|=u}r+=t.encode(n)}while(i>0);return r};r.decode=function base64VLQ_decode(e,r,n){var i=e.length;var s=0;var l=0;var c,p;do{if(r>=i){throw new Error("Expected more digits in base 64 VLQ value.")}p=t.decode(e.charCodeAt(r++));if(p===-1){throw new Error("Invalid base64 digit: "+e.charAt(r-1))}c=!!(p&u);p&=a;s=s+(p<{var n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");r.encode=function(e){if(0<=e&&e{r.GREATEST_LOWER_BOUND=1;r.LEAST_UPPER_BOUND=2;function recursiveSearch(e,n,t,o,i,a){var u=Math.floor((n-e)/2)+e;var s=i(t,o[u],true);if(s===0){return u}else if(s>0){if(n-u>1){return recursiveSearch(u,n,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return n1){return recursiveSearch(e,u,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return u}else{return e<0?-1:e}}}r.search=function search(e,n,t,o){if(n.length===0){return-1}var i=recursiveSearch(-1,n.length,e,n,t,o||r.GREATEST_LOWER_BOUND);if(i<0){return-1}while(i-1>=0){if(t(n[i],n[i-1],true)!==0){break}--i}return i}},24:(e,r,n)=>{var t=n(297);function generatedPositionAfter(e,r){var n=e.generatedLine;var o=r.generatedLine;var i=e.generatedColumn;var a=r.generatedColumn;return o>n||o==n&&a>=i||t.compareByGeneratedPositionsInflated(e,r)<=0}function MappingList(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}MappingList.prototype.unsortedForEach=function MappingList_forEach(e,r){this._array.forEach(e,r)};MappingList.prototype.add=function MappingList_add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}};MappingList.prototype.toArray=function MappingList_toArray(){if(!this._sorted){this._array.sort(t.compareByGeneratedPositionsInflated);this._sorted=true}return this._array};r.P=MappingList},299:(e,r)=>{function swap(e,r,n){var t=e[r];e[r]=e[n];e[n]=t}function randomIntInRange(e,r){return Math.round(e+Math.random()*(r-e))}function doQuickSort(e,r,n,t){if(n{var t;var o=n(297);var i=n(197);var a=n(517).C;var u=n(818);var s=n(299).g;function SourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}return n.sections!=null?new IndexedSourceMapConsumer(n,r):new BasicSourceMapConsumer(n,r)}SourceMapConsumer.fromSourceMap=function(e,r){return BasicSourceMapConsumer.fromSourceMap(e,r)};SourceMapConsumer.prototype._version=3;SourceMapConsumer.prototype.__generatedMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_generatedMappings",{configurable:true,enumerable:true,get:function(){if(!this.__generatedMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__generatedMappings}});SourceMapConsumer.prototype.__originalMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_originalMappings",{configurable:true,enumerable:true,get:function(){if(!this.__originalMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__originalMappings}});SourceMapConsumer.prototype._charIsMappingSeparator=function SourceMapConsumer_charIsMappingSeparator(e,r){var n=e.charAt(r);return n===";"||n===","};SourceMapConsumer.prototype._parseMappings=function SourceMapConsumer_parseMappings(e,r){throw new Error("Subclasses must implement _parseMappings")};SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;SourceMapConsumer.prototype.eachMapping=function SourceMapConsumer_eachMapping(e,r,n){var t=r||null;var i=n||SourceMapConsumer.GENERATED_ORDER;var a;switch(i){case SourceMapConsumer.GENERATED_ORDER:a=this._generatedMappings;break;case SourceMapConsumer.ORIGINAL_ORDER:a=this._originalMappings;break;default:throw new Error("Unknown order of iteration.")}var u=this.sourceRoot;a.map((function(e){var r=e.source===null?null:this._sources.at(e.source);r=o.computeSourceURL(u,r,this._sourceMapURL);return{source:r,generatedLine:e.generatedLine,generatedColumn:e.generatedColumn,originalLine:e.originalLine,originalColumn:e.originalColumn,name:e.name===null?null:this._names.at(e.name)}}),this).forEach(e,t)};SourceMapConsumer.prototype.allGeneratedPositionsFor=function SourceMapConsumer_allGeneratedPositionsFor(e){var r=o.getArg(e,"line");var n={source:o.getArg(e,"source"),originalLine:r,originalColumn:o.getArg(e,"column",0)};n.source=this._findSourceIndex(n.source);if(n.source<0){return[]}var t=[];var a=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,i.LEAST_UPPER_BOUND);if(a>=0){var u=this._originalMappings[a];if(e.column===undefined){var s=u.originalLine;while(u&&u.originalLine===s){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}else{var l=u.originalColumn;while(u&&u.originalLine===r&&u.originalColumn==l){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}}return t};r.SourceMapConsumer=SourceMapConsumer;function BasicSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sources");var u=o.getArg(n,"names",[]);var s=o.getArg(n,"sourceRoot",null);var l=o.getArg(n,"sourcesContent",null);var c=o.getArg(n,"mappings");var p=o.getArg(n,"file",null);if(t!=this._version){throw new Error("Unsupported version: "+t)}if(s){s=o.normalize(s)}i=i.map(String).map(o.normalize).map((function(e){return s&&o.isAbsolute(s)&&o.isAbsolute(e)?o.relative(s,e):e}));this._names=a.fromArray(u.map(String),true);this._sources=a.fromArray(i,true);this._absoluteSources=this._sources.toArray().map((function(e){return o.computeSourceURL(s,e,r)}));this.sourceRoot=s;this.sourcesContent=l;this._mappings=c;this._sourceMapURL=r;this.file=p}BasicSourceMapConsumer.prototype=Object.create(SourceMapConsumer.prototype);BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;BasicSourceMapConsumer.prototype._findSourceIndex=function(e){var r=e;if(this.sourceRoot!=null){r=o.relative(this.sourceRoot,r)}if(this._sources.has(r)){return this._sources.indexOf(r)}var n;for(n=0;n1){v.source=l+_[1];l+=_[1];v.originalLine=i+_[2];i=v.originalLine;v.originalLine+=1;v.originalColumn=a+_[3];a=v.originalColumn;if(_.length>4){v.name=c+_[4];c+=_[4]}}m.push(v);if(typeof v.originalLine==="number"){h.push(v)}}}s(m,o.compareByGeneratedPositionsDeflated);this.__generatedMappings=m;s(h,o.compareByOriginalPositions);this.__originalMappings=h};BasicSourceMapConsumer.prototype._findMapping=function SourceMapConsumer_findMapping(e,r,n,t,o,a){if(e[n]<=0){throw new TypeError("Line must be greater than or equal to 1, got "+e[n])}if(e[t]<0){throw new TypeError("Column must be greater than or equal to 0, got "+e[t])}return i.search(e,r,o,a)};BasicSourceMapConsumer.prototype.computeColumnSpans=function SourceMapConsumer_computeColumnSpans(){for(var e=0;e=0){var t=this._generatedMappings[n];if(t.generatedLine===r.generatedLine){var i=o.getArg(t,"source",null);if(i!==null){i=this._sources.at(i);i=o.computeSourceURL(this.sourceRoot,i,this._sourceMapURL)}var a=o.getArg(t,"name",null);if(a!==null){a=this._names.at(a)}return{source:i,line:o.getArg(t,"originalLine",null),column:o.getArg(t,"originalColumn",null),name:a}}}return{source:null,line:null,column:null,name:null}};BasicSourceMapConsumer.prototype.hasContentsOfAllSources=function BasicSourceMapConsumer_hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))};BasicSourceMapConsumer.prototype.sourceContentFor=function SourceMapConsumer_sourceContentFor(e,r){if(!this.sourcesContent){return null}var n=this._findSourceIndex(e);if(n>=0){return this.sourcesContent[n]}var t=e;if(this.sourceRoot!=null){t=o.relative(this.sourceRoot,t)}var i;if(this.sourceRoot!=null&&(i=o.urlParse(this.sourceRoot))){var a=t.replace(/^file:\/\//,"");if(i.scheme=="file"&&this._sources.has(a)){return this.sourcesContent[this._sources.indexOf(a)]}if((!i.path||i.path=="/")&&this._sources.has("/"+t)){return this.sourcesContent[this._sources.indexOf("/"+t)]}}if(r){return null}else{throw new Error('"'+t+'" is not in the SourceMap.')}};BasicSourceMapConsumer.prototype.generatedPositionFor=function SourceMapConsumer_generatedPositionFor(e){var r=o.getArg(e,"source");r=this._findSourceIndex(r);if(r<0){return{line:null,column:null,lastColumn:null}}var n={source:r,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};var t=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND));if(t>=0){var i=this._originalMappings[t];if(i.source===n.source){return{line:o.getArg(i,"generatedLine",null),column:o.getArg(i,"generatedColumn",null),lastColumn:o.getArg(i,"lastGeneratedColumn",null)}}}return{line:null,column:null,lastColumn:null}};t=BasicSourceMapConsumer;function IndexedSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sections");if(t!=this._version){throw new Error("Unsupported version: "+t)}this._sources=new a;this._names=new a;var u={line:-1,column:0};this._sections=i.map((function(e){if(e.url){throw new Error("Support for url field in sections not implemented.")}var n=o.getArg(e,"offset");var t=o.getArg(n,"line");var i=o.getArg(n,"column");if(t{var t=n(818);var o=n(297);var i=n(517).C;var a=n(24).P;function SourceMapGenerator(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new i;this._names=new i;this._mappings=new a;this._sourcesContents=null}SourceMapGenerator.prototype._version=3;SourceMapGenerator.fromSourceMap=function SourceMapGenerator_fromSourceMap(e){var r=e.sourceRoot;var n=new SourceMapGenerator({file:e.file,sourceRoot:r});e.eachMapping((function(e){var t={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){t.source=e.source;if(r!=null){t.source=o.relative(r,t.source)}t.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){t.name=e.name}}n.addMapping(t)}));e.sources.forEach((function(t){var i=t;if(r!==null){i=o.relative(r,t)}if(!n._sources.has(i)){n._sources.add(i)}var a=e.sourceContentFor(t);if(a!=null){n.setSourceContent(t,a)}}));return n};SourceMapGenerator.prototype.addMapping=function SourceMapGenerator_addMapping(e){var r=o.getArg(e,"generated");var n=o.getArg(e,"original",null);var t=o.getArg(e,"source",null);var i=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(r,n,t,i)}if(t!=null){t=String(t);if(!this._sources.has(t)){this._sources.add(t)}}if(i!=null){i=String(i);if(!this._names.has(i)){this._names.add(i)}}this._mappings.add({generatedLine:r.line,generatedColumn:r.column,originalLine:n!=null&&n.line,originalColumn:n!=null&&n.column,source:t,name:i})};SourceMapGenerator.prototype.setSourceContent=function SourceMapGenerator_setSourceContent(e,r){var n=e;if(this._sourceRoot!=null){n=o.relative(this._sourceRoot,n)}if(r!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(n)]=r}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(n)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}};SourceMapGenerator.prototype.applySourceMap=function SourceMapGenerator_applySourceMap(e,r,n){var t=r;if(r==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}t=e.file}var a=this._sourceRoot;if(a!=null){t=o.relative(a,t)}var u=new i;var s=new i;this._mappings.unsortedForEach((function(r){if(r.source===t&&r.originalLine!=null){var i=e.originalPositionFor({line:r.originalLine,column:r.originalColumn});if(i.source!=null){r.source=i.source;if(n!=null){r.source=o.join(n,r.source)}if(a!=null){r.source=o.relative(a,r.source)}r.originalLine=i.line;r.originalColumn=i.column;if(i.name!=null){r.name=i.name}}}var l=r.source;if(l!=null&&!u.has(l)){u.add(l)}var c=r.name;if(c!=null&&!s.has(c)){s.add(c)}}),this);this._sources=u;this._names=s;e.sources.forEach((function(r){var t=e.sourceContentFor(r);if(t!=null){if(n!=null){r=o.join(n,r)}if(a!=null){r=o.relative(a,r)}this.setSourceContent(r,t)}}),this)};SourceMapGenerator.prototype._validateMapping=function SourceMapGenerator_validateMapping(e,r,n,t){if(r&&typeof r.line!=="number"&&typeof r.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!r&&!n&&!t){return}else if(e&&"line"in e&&"column"in e&&r&&"line"in r&&"column"in r&&e.line>0&&e.column>=0&&r.line>0&&r.column>=0&&n){return}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:r,name:t}))}};SourceMapGenerator.prototype._serializeMappings=function SourceMapGenerator_serializeMappings(){var e=0;var r=1;var n=0;var i=0;var a=0;var u=0;var s="";var l;var c;var p;var f;var g=this._mappings.toArray();for(var d=0,h=g.length;d0){if(!o.compareByGeneratedPositionsInflated(c,g[d-1])){continue}l+=","}}l+=t.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);l+=t.encode(f-u);u=f;l+=t.encode(c.originalLine-1-i);i=c.originalLine-1;l+=t.encode(c.originalColumn-n);n=c.originalColumn;if(c.name!=null){p=this._names.indexOf(c.name);l+=t.encode(p-a);a=p}}s+=l}return s};SourceMapGenerator.prototype._generateSourcesContent=function SourceMapGenerator_generateSourcesContent(e,r){return e.map((function(e){if(!this._sourcesContents){return null}if(r!=null){e=o.relative(r,e)}var n=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null}),this)};SourceMapGenerator.prototype.toJSON=function SourceMapGenerator_toJSON(){var e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e};SourceMapGenerator.prototype.toString=function SourceMapGenerator_toString(){return JSON.stringify(this.toJSON())};r.x=SourceMapGenerator},565:(e,r,n)=>{var t;var o=n(163).x;var i=n(297);var a=/(\r?\n)/;var u=10;var s="$$$isSourceNode$$$";function SourceNode(e,r,n,t,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=r==null?null:r;this.source=n==null?null:n;this.name=o==null?null:o;this[s]=true;if(t!=null)this.add(t)}SourceNode.fromStringWithSourceMap=function SourceNode_fromStringWithSourceMap(e,r,n){var t=new SourceNode;var o=e.split(a);var u=0;var shiftNextLine=function(){var e=getNextLine();var r=getNextLine()||"";return e+r;function getNextLine(){return u=0;r--){this.prepend(e[r])}}else if(e[s]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this};SourceNode.prototype.walk=function SourceNode_walk(e){var r;for(var n=0,t=this.children.length;n0){r=[];for(n=0;n{function getArg(e,r,n){if(r in e){return e[r]}else if(arguments.length===3){return n}else{throw new Error('"'+r+'" is a required argument.')}}r.getArg=getArg;var n=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;var t=/^data:.+\,.+$/;function urlParse(e){var r=e.match(n);if(!r){return null}return{scheme:r[1],auth:r[2],host:r[3],port:r[4],path:r[5]}}r.urlParse=urlParse;function urlGenerate(e){var r="";if(e.scheme){r+=e.scheme+":"}r+="//";if(e.auth){r+=e.auth+"@"}if(e.host){r+=e.host}if(e.port){r+=":"+e.port}if(e.path){r+=e.path}return r}r.urlGenerate=urlGenerate;function normalize(e){var n=e;var t=urlParse(e);if(t){if(!t.path){return e}n=t.path}var o=r.isAbsolute(n);var i=n.split(/\/+/);for(var a,u=0,s=i.length-1;s>=0;s--){a=i[s];if(a==="."){i.splice(s,1)}else if(a===".."){u++}else if(u>0){if(a===""){i.splice(s+1,u);u=0}else{i.splice(s,2);u--}}}n=i.join("/");if(n===""){n=o?"/":"."}if(t){t.path=n;return urlGenerate(t)}return n}r.normalize=normalize;function join(e,r){if(e===""){e="."}if(r===""){r="."}var n=urlParse(r);var o=urlParse(e);if(o){e=o.path||"/"}if(n&&!n.scheme){if(o){n.scheme=o.scheme}return urlGenerate(n)}if(n||r.match(t)){return r}if(o&&!o.host&&!o.path){o.host=r;return urlGenerate(o)}var i=r.charAt(0)==="/"?r:normalize(e.replace(/\/+$/,"")+"/"+r);if(o){o.path=i;return urlGenerate(o)}return i}r.join=join;r.isAbsolute=function(e){return e.charAt(0)==="/"||n.test(e)};function relative(e,r){if(e===""){e="."}e=e.replace(/\/$/,"");var n=0;while(r.indexOf(e+"/")!==0){var t=e.lastIndexOf("/");if(t<0){return r}e=e.slice(0,t);if(e.match(/^([^\/]+:\/)?\/*$/)){return r}++n}return Array(n+1).join("../")+r.substr(e.length+1)}r.relative=relative;var o=function(){var e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}r.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}r.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}var r=e.length;if(r<9){return false}if(e.charCodeAt(r-1)!==95||e.charCodeAt(r-2)!==95||e.charCodeAt(r-3)!==111||e.charCodeAt(r-4)!==116||e.charCodeAt(r-5)!==111||e.charCodeAt(r-6)!==114||e.charCodeAt(r-7)!==112||e.charCodeAt(r-8)!==95||e.charCodeAt(r-9)!==95){return false}for(var n=r-10;n>=0;n--){if(e.charCodeAt(n)!==36){return false}}return true}function compareByOriginalPositions(e,r,n){var t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0||n){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0){return t}t=e.generatedLine-r.generatedLine;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByOriginalPositions=compareByOriginalPositions;function compareByGeneratedPositionsDeflated(e,r,n){var t=e.generatedLine-r.generatedLine;if(t!==0){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0||n){return t}t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsDeflated=compareByGeneratedPositionsDeflated;function strcmp(e,r){if(e===r){return 0}if(e===null){return 1}if(r===null){return-1}if(e>r){return 1}return-1}function compareByGeneratedPositionsInflated(e,r){var n=e.generatedLine-r.generatedLine;if(n!==0){return n}n=e.generatedColumn-r.generatedColumn;if(n!==0){return n}n=strcmp(e.source,r.source);if(n!==0){return n}n=e.originalLine-r.originalLine;if(n!==0){return n}n=e.originalColumn-r.originalColumn;if(n!==0){return n}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}r.parseSourceMapInput=parseSourceMapInput;function computeSourceURL(e,r,n){r=r||"";if(e){if(e[e.length-1]!=="/"&&r[0]!=="/"){e+="/"}r=e+r}if(n){var t=urlParse(n);if(!t){throw new Error("sourceMapURL could not be parsed")}if(t.path){var o=t.path.lastIndexOf("/");if(o>=0){t.path=t.path.substring(0,o+1)}}r=join(urlGenerate(t),r)}return normalize(r)}r.computeSourceURL=computeSourceURL},927:(e,r,n)=>{n(163).x;r.SourceMapConsumer=n(684).SourceMapConsumer;n(565)},896:e=>{"use strict";e.exports=require("fs")},928:e=>{"use strict";e.exports=require("path")}};var r={};function __webpack_require__(n){var t=r[n];if(t!==undefined){return t.exports}var o=r[n]={id:n,loaded:false,exports:{}};var i=true;try{e[n](o,o.exports,__webpack_require__);i=false}finally{if(i)delete r[n]}o.loaded=true;return o.exports}(()=>{__webpack_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __webpack_require__!=="undefined")__webpack_require__.ab=__dirname+"/";var n={};__webpack_require__(599).install();module.exports=n})(); \ No newline at end of file diff --git a/dist/sourcemap-register.js b/dist/sourcemap-register.js deleted file mode 100644 index cb1fb13..0000000 --- a/dist/sourcemap-register.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{var e={296:e=>{var r=Object.prototype.toString;var n=typeof Buffer!=="undefined"&&typeof Buffer.alloc==="function"&&typeof Buffer.allocUnsafe==="function"&&typeof Buffer.from==="function";function isArrayBuffer(e){return r.call(e).slice(8,-1)==="ArrayBuffer"}function fromArrayBuffer(e,r,t){r>>>=0;var o=e.byteLength-r;if(o<0){throw new RangeError("'offset' is out of bounds")}if(t===undefined){t=o}else{t>>>=0;if(t>o){throw new RangeError("'length' is out of bounds")}}return n?Buffer.from(e.slice(r,r+t)):new Buffer(new Uint8Array(e.slice(r,r+t)))}function fromString(e,r){if(typeof r!=="string"||r===""){r="utf8"}if(!Buffer.isEncoding(r)){throw new TypeError('"encoding" must be a valid string encoding')}return n?Buffer.from(e,r):new Buffer(e,r)}function bufferFrom(e,r,t){if(typeof e==="number"){throw new TypeError('"value" argument must not be a number')}if(isArrayBuffer(e)){return fromArrayBuffer(e,r,t)}if(typeof e==="string"){return fromString(e,r)}return n?Buffer.from(e):new Buffer(e)}e.exports=bufferFrom},599:(e,r,n)=>{e=n.nmd(e);var t=n(927).SourceMapConsumer;var o=n(928);var i;try{i=n(896);if(!i.existsSync||!i.readFileSync){i=null}}catch(e){}var a=n(296);function dynamicRequire(e,r){return e.require(r)}var u=false;var s=false;var l=false;var c="auto";var p={};var f={};var g=/^data:application\/json[^,]+base64,/;var d=[];var h=[];function isInBrowser(){if(c==="browser")return true;if(c==="node")return false;return typeof window!=="undefined"&&typeof XMLHttpRequest==="function"&&!(window.require&&window.module&&window.process&&window.process.type==="renderer")}function hasGlobalProcessEventEmitter(){return typeof process==="object"&&process!==null&&typeof process.on==="function"}function globalProcessVersion(){if(typeof process==="object"&&process!==null){return process.version}else{return""}}function globalProcessStderr(){if(typeof process==="object"&&process!==null){return process.stderr}}function globalProcessExit(e){if(typeof process==="object"&&process!==null&&typeof process.exit==="function"){return process.exit(e)}}function handlerExec(e){return function(r){for(var n=0;n"}var n=this.getLineNumber();if(n!=null){r+=":"+n;var t=this.getColumnNumber();if(t){r+=":"+t}}}var o="";var i=this.getFunctionName();var a=true;var u=this.isConstructor();var s=!(this.isToplevel()||u);if(s){var l=this.getTypeName();if(l==="[object Object]"){l="null"}var c=this.getMethodName();if(i){if(l&&i.indexOf(l)!=0){o+=l+"."}o+=i;if(c&&i.indexOf("."+c)!=i.length-c.length-1){o+=" [as "+c+"]"}}else{o+=l+"."+(c||"")}}else if(u){o+="new "+(i||"")}else if(i){o+=i}else{o+=r;a=false}if(a){o+=" ("+r+")"}return o}function cloneCallSite(e){var r={};Object.getOwnPropertyNames(Object.getPrototypeOf(e)).forEach((function(n){r[n]=/^(?:is|get)/.test(n)?function(){return e[n].call(e)}:e[n]}));r.toString=CallSiteToString;return r}function wrapCallSite(e,r){if(r===undefined){r={nextPosition:null,curPosition:null}}if(e.isNative()){r.curPosition=null;return e}var n=e.getFileName()||e.getScriptNameOrSourceURL();if(n){var t=e.getLineNumber();var o=e.getColumnNumber()-1;var i=/^v(10\.1[6-9]|10\.[2-9][0-9]|10\.[0-9]{3,}|1[2-9]\d*|[2-9]\d|\d{3,}|11\.11)/;var a=i.test(globalProcessVersion())?0:62;if(t===1&&o>a&&!isInBrowser()&&!e.isEval()){o-=a}var u=mapSourcePosition({source:n,line:t,column:o});r.curPosition=u;e=cloneCallSite(e);var s=e.getFunctionName;e.getFunctionName=function(){if(r.nextPosition==null){return s()}return r.nextPosition.name||s()};e.getFileName=function(){return u.source};e.getLineNumber=function(){return u.line};e.getColumnNumber=function(){return u.column+1};e.getScriptNameOrSourceURL=function(){return u.source};return e}var l=e.isEval()&&e.getEvalOrigin();if(l){l=mapEvalOrigin(l);e=cloneCallSite(e);e.getEvalOrigin=function(){return l};return e}return e}function prepareStackTrace(e,r){if(l){p={};f={}}var n=e.name||"Error";var t=e.message||"";var o=n+": "+t;var i={nextPosition:null,curPosition:null};var a=[];for(var u=r.length-1;u>=0;u--){a.push("\n at "+wrapCallSite(r[u],i));i.nextPosition=i.curPosition}i.curPosition=i.nextPosition=null;return o+a.reverse().join("")}function getErrorSource(e){var r=/\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(e.stack);if(r){var n=r[1];var t=+r[2];var o=+r[3];var a=p[n];if(!a&&i&&i.existsSync(n)){try{a=i.readFileSync(n,"utf8")}catch(e){a=""}}if(a){var u=a.split(/(?:\r\n|\r|\n)/)[t-1];if(u){return n+":"+t+"\n"+u+"\n"+new Array(o).join(" ")+"^"}}}return null}function printErrorAndExit(e){var r=getErrorSource(e);var n=globalProcessStderr();if(n&&n._handle&&n._handle.setBlocking){n._handle.setBlocking(true)}if(r){console.error();console.error(r)}console.error(e.stack);globalProcessExit(1)}function shimEmitUncaughtException(){var e=process.emit;process.emit=function(r){if(r==="uncaughtException"){var n=arguments[1]&&arguments[1].stack;var t=this.listeners(r).length>0;if(n&&!t){return printErrorAndExit(arguments[1])}}return e.apply(this,arguments)}}var S=d.slice(0);var _=h.slice(0);r.wrapCallSite=wrapCallSite;r.getErrorSource=getErrorSource;r.mapSourcePosition=mapSourcePosition;r.retrieveSourceMap=v;r.install=function(r){r=r||{};if(r.environment){c=r.environment;if(["node","browser","auto"].indexOf(c)===-1){throw new Error("environment "+c+" was unknown. Available options are {auto, browser, node}")}}if(r.retrieveFile){if(r.overrideRetrieveFile){d.length=0}d.unshift(r.retrieveFile)}if(r.retrieveSourceMap){if(r.overrideRetrieveSourceMap){h.length=0}h.unshift(r.retrieveSourceMap)}if(r.hookRequire&&!isInBrowser()){var n=dynamicRequire(e,"module");var t=n.prototype._compile;if(!t.__sourceMapSupport){n.prototype._compile=function(e,r){p[r]=e;f[r]=undefined;return t.call(this,e,r)};n.prototype._compile.__sourceMapSupport=true}}if(!l){l="emptyCacheBetweenOperations"in r?r.emptyCacheBetweenOperations:false}if(!u){u=true;Error.prepareStackTrace=prepareStackTrace}if(!s){var o="handleUncaughtExceptions"in r?r.handleUncaughtExceptions:true;try{var i=dynamicRequire(e,"worker_threads");if(i.isMainThread===false){o=false}}catch(e){}if(o&&hasGlobalProcessEventEmitter()){s=true;shimEmitUncaughtException()}}};r.resetRetrieveHandlers=function(){d.length=0;h.length=0;d=S.slice(0);h=_.slice(0);v=handlerExec(h);m=handlerExec(d)}},517:(e,r,n)=>{var t=n(297);var o=Object.prototype.hasOwnProperty;var i=typeof Map!=="undefined";function ArraySet(){this._array=[];this._set=i?new Map:Object.create(null)}ArraySet.fromArray=function ArraySet_fromArray(e,r){var n=new ArraySet;for(var t=0,o=e.length;t=0){return r}}else{var n=t.toSetString(e);if(o.call(this._set,n)){return this._set[n]}}throw new Error('"'+e+'" is not in the set.')};ArraySet.prototype.at=function ArraySet_at(e){if(e>=0&&e{var t=n(158);var o=5;var i=1<>1;return r?-n:n}r.encode=function base64VLQ_encode(e){var r="";var n;var i=toVLQSigned(e);do{n=i&a;i>>>=o;if(i>0){n|=u}r+=t.encode(n)}while(i>0);return r};r.decode=function base64VLQ_decode(e,r,n){var i=e.length;var s=0;var l=0;var c,p;do{if(r>=i){throw new Error("Expected more digits in base 64 VLQ value.")}p=t.decode(e.charCodeAt(r++));if(p===-1){throw new Error("Invalid base64 digit: "+e.charAt(r-1))}c=!!(p&u);p&=a;s=s+(p<{var n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");r.encode=function(e){if(0<=e&&e{r.GREATEST_LOWER_BOUND=1;r.LEAST_UPPER_BOUND=2;function recursiveSearch(e,n,t,o,i,a){var u=Math.floor((n-e)/2)+e;var s=i(t,o[u],true);if(s===0){return u}else if(s>0){if(n-u>1){return recursiveSearch(u,n,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return n1){return recursiveSearch(e,u,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return u}else{return e<0?-1:e}}}r.search=function search(e,n,t,o){if(n.length===0){return-1}var i=recursiveSearch(-1,n.length,e,n,t,o||r.GREATEST_LOWER_BOUND);if(i<0){return-1}while(i-1>=0){if(t(n[i],n[i-1],true)!==0){break}--i}return i}},24:(e,r,n)=>{var t=n(297);function generatedPositionAfter(e,r){var n=e.generatedLine;var o=r.generatedLine;var i=e.generatedColumn;var a=r.generatedColumn;return o>n||o==n&&a>=i||t.compareByGeneratedPositionsInflated(e,r)<=0}function MappingList(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}MappingList.prototype.unsortedForEach=function MappingList_forEach(e,r){this._array.forEach(e,r)};MappingList.prototype.add=function MappingList_add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}};MappingList.prototype.toArray=function MappingList_toArray(){if(!this._sorted){this._array.sort(t.compareByGeneratedPositionsInflated);this._sorted=true}return this._array};r.P=MappingList},299:(e,r)=>{function swap(e,r,n){var t=e[r];e[r]=e[n];e[n]=t}function randomIntInRange(e,r){return Math.round(e+Math.random()*(r-e))}function doQuickSort(e,r,n,t){if(n{var t;var o=n(297);var i=n(197);var a=n(517).C;var u=n(818);var s=n(299).g;function SourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}return n.sections!=null?new IndexedSourceMapConsumer(n,r):new BasicSourceMapConsumer(n,r)}SourceMapConsumer.fromSourceMap=function(e,r){return BasicSourceMapConsumer.fromSourceMap(e,r)};SourceMapConsumer.prototype._version=3;SourceMapConsumer.prototype.__generatedMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_generatedMappings",{configurable:true,enumerable:true,get:function(){if(!this.__generatedMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__generatedMappings}});SourceMapConsumer.prototype.__originalMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_originalMappings",{configurable:true,enumerable:true,get:function(){if(!this.__originalMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__originalMappings}});SourceMapConsumer.prototype._charIsMappingSeparator=function SourceMapConsumer_charIsMappingSeparator(e,r){var n=e.charAt(r);return n===";"||n===","};SourceMapConsumer.prototype._parseMappings=function SourceMapConsumer_parseMappings(e,r){throw new Error("Subclasses must implement _parseMappings")};SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;SourceMapConsumer.prototype.eachMapping=function SourceMapConsumer_eachMapping(e,r,n){var t=r||null;var i=n||SourceMapConsumer.GENERATED_ORDER;var a;switch(i){case SourceMapConsumer.GENERATED_ORDER:a=this._generatedMappings;break;case SourceMapConsumer.ORIGINAL_ORDER:a=this._originalMappings;break;default:throw new Error("Unknown order of iteration.")}var u=this.sourceRoot;a.map((function(e){var r=e.source===null?null:this._sources.at(e.source);r=o.computeSourceURL(u,r,this._sourceMapURL);return{source:r,generatedLine:e.generatedLine,generatedColumn:e.generatedColumn,originalLine:e.originalLine,originalColumn:e.originalColumn,name:e.name===null?null:this._names.at(e.name)}}),this).forEach(e,t)};SourceMapConsumer.prototype.allGeneratedPositionsFor=function SourceMapConsumer_allGeneratedPositionsFor(e){var r=o.getArg(e,"line");var n={source:o.getArg(e,"source"),originalLine:r,originalColumn:o.getArg(e,"column",0)};n.source=this._findSourceIndex(n.source);if(n.source<0){return[]}var t=[];var a=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,i.LEAST_UPPER_BOUND);if(a>=0){var u=this._originalMappings[a];if(e.column===undefined){var s=u.originalLine;while(u&&u.originalLine===s){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}else{var l=u.originalColumn;while(u&&u.originalLine===r&&u.originalColumn==l){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}}return t};r.SourceMapConsumer=SourceMapConsumer;function BasicSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sources");var u=o.getArg(n,"names",[]);var s=o.getArg(n,"sourceRoot",null);var l=o.getArg(n,"sourcesContent",null);var c=o.getArg(n,"mappings");var p=o.getArg(n,"file",null);if(t!=this._version){throw new Error("Unsupported version: "+t)}if(s){s=o.normalize(s)}i=i.map(String).map(o.normalize).map((function(e){return s&&o.isAbsolute(s)&&o.isAbsolute(e)?o.relative(s,e):e}));this._names=a.fromArray(u.map(String),true);this._sources=a.fromArray(i,true);this._absoluteSources=this._sources.toArray().map((function(e){return o.computeSourceURL(s,e,r)}));this.sourceRoot=s;this.sourcesContent=l;this._mappings=c;this._sourceMapURL=r;this.file=p}BasicSourceMapConsumer.prototype=Object.create(SourceMapConsumer.prototype);BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;BasicSourceMapConsumer.prototype._findSourceIndex=function(e){var r=e;if(this.sourceRoot!=null){r=o.relative(this.sourceRoot,r)}if(this._sources.has(r)){return this._sources.indexOf(r)}var n;for(n=0;n1){v.source=l+_[1];l+=_[1];v.originalLine=i+_[2];i=v.originalLine;v.originalLine+=1;v.originalColumn=a+_[3];a=v.originalColumn;if(_.length>4){v.name=c+_[4];c+=_[4]}}m.push(v);if(typeof v.originalLine==="number"){h.push(v)}}}s(m,o.compareByGeneratedPositionsDeflated);this.__generatedMappings=m;s(h,o.compareByOriginalPositions);this.__originalMappings=h};BasicSourceMapConsumer.prototype._findMapping=function SourceMapConsumer_findMapping(e,r,n,t,o,a){if(e[n]<=0){throw new TypeError("Line must be greater than or equal to 1, got "+e[n])}if(e[t]<0){throw new TypeError("Column must be greater than or equal to 0, got "+e[t])}return i.search(e,r,o,a)};BasicSourceMapConsumer.prototype.computeColumnSpans=function SourceMapConsumer_computeColumnSpans(){for(var e=0;e=0){var t=this._generatedMappings[n];if(t.generatedLine===r.generatedLine){var i=o.getArg(t,"source",null);if(i!==null){i=this._sources.at(i);i=o.computeSourceURL(this.sourceRoot,i,this._sourceMapURL)}var a=o.getArg(t,"name",null);if(a!==null){a=this._names.at(a)}return{source:i,line:o.getArg(t,"originalLine",null),column:o.getArg(t,"originalColumn",null),name:a}}}return{source:null,line:null,column:null,name:null}};BasicSourceMapConsumer.prototype.hasContentsOfAllSources=function BasicSourceMapConsumer_hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))};BasicSourceMapConsumer.prototype.sourceContentFor=function SourceMapConsumer_sourceContentFor(e,r){if(!this.sourcesContent){return null}var n=this._findSourceIndex(e);if(n>=0){return this.sourcesContent[n]}var t=e;if(this.sourceRoot!=null){t=o.relative(this.sourceRoot,t)}var i;if(this.sourceRoot!=null&&(i=o.urlParse(this.sourceRoot))){var a=t.replace(/^file:\/\//,"");if(i.scheme=="file"&&this._sources.has(a)){return this.sourcesContent[this._sources.indexOf(a)]}if((!i.path||i.path=="/")&&this._sources.has("/"+t)){return this.sourcesContent[this._sources.indexOf("/"+t)]}}if(r){return null}else{throw new Error('"'+t+'" is not in the SourceMap.')}};BasicSourceMapConsumer.prototype.generatedPositionFor=function SourceMapConsumer_generatedPositionFor(e){var r=o.getArg(e,"source");r=this._findSourceIndex(r);if(r<0){return{line:null,column:null,lastColumn:null}}var n={source:r,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};var t=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND));if(t>=0){var i=this._originalMappings[t];if(i.source===n.source){return{line:o.getArg(i,"generatedLine",null),column:o.getArg(i,"generatedColumn",null),lastColumn:o.getArg(i,"lastGeneratedColumn",null)}}}return{line:null,column:null,lastColumn:null}};t=BasicSourceMapConsumer;function IndexedSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sections");if(t!=this._version){throw new Error("Unsupported version: "+t)}this._sources=new a;this._names=new a;var u={line:-1,column:0};this._sections=i.map((function(e){if(e.url){throw new Error("Support for url field in sections not implemented.")}var n=o.getArg(e,"offset");var t=o.getArg(n,"line");var i=o.getArg(n,"column");if(t{var t=n(818);var o=n(297);var i=n(517).C;var a=n(24).P;function SourceMapGenerator(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new i;this._names=new i;this._mappings=new a;this._sourcesContents=null}SourceMapGenerator.prototype._version=3;SourceMapGenerator.fromSourceMap=function SourceMapGenerator_fromSourceMap(e){var r=e.sourceRoot;var n=new SourceMapGenerator({file:e.file,sourceRoot:r});e.eachMapping((function(e){var t={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){t.source=e.source;if(r!=null){t.source=o.relative(r,t.source)}t.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){t.name=e.name}}n.addMapping(t)}));e.sources.forEach((function(t){var i=t;if(r!==null){i=o.relative(r,t)}if(!n._sources.has(i)){n._sources.add(i)}var a=e.sourceContentFor(t);if(a!=null){n.setSourceContent(t,a)}}));return n};SourceMapGenerator.prototype.addMapping=function SourceMapGenerator_addMapping(e){var r=o.getArg(e,"generated");var n=o.getArg(e,"original",null);var t=o.getArg(e,"source",null);var i=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(r,n,t,i)}if(t!=null){t=String(t);if(!this._sources.has(t)){this._sources.add(t)}}if(i!=null){i=String(i);if(!this._names.has(i)){this._names.add(i)}}this._mappings.add({generatedLine:r.line,generatedColumn:r.column,originalLine:n!=null&&n.line,originalColumn:n!=null&&n.column,source:t,name:i})};SourceMapGenerator.prototype.setSourceContent=function SourceMapGenerator_setSourceContent(e,r){var n=e;if(this._sourceRoot!=null){n=o.relative(this._sourceRoot,n)}if(r!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(n)]=r}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(n)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}};SourceMapGenerator.prototype.applySourceMap=function SourceMapGenerator_applySourceMap(e,r,n){var t=r;if(r==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}t=e.file}var a=this._sourceRoot;if(a!=null){t=o.relative(a,t)}var u=new i;var s=new i;this._mappings.unsortedForEach((function(r){if(r.source===t&&r.originalLine!=null){var i=e.originalPositionFor({line:r.originalLine,column:r.originalColumn});if(i.source!=null){r.source=i.source;if(n!=null){r.source=o.join(n,r.source)}if(a!=null){r.source=o.relative(a,r.source)}r.originalLine=i.line;r.originalColumn=i.column;if(i.name!=null){r.name=i.name}}}var l=r.source;if(l!=null&&!u.has(l)){u.add(l)}var c=r.name;if(c!=null&&!s.has(c)){s.add(c)}}),this);this._sources=u;this._names=s;e.sources.forEach((function(r){var t=e.sourceContentFor(r);if(t!=null){if(n!=null){r=o.join(n,r)}if(a!=null){r=o.relative(a,r)}this.setSourceContent(r,t)}}),this)};SourceMapGenerator.prototype._validateMapping=function SourceMapGenerator_validateMapping(e,r,n,t){if(r&&typeof r.line!=="number"&&typeof r.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!r&&!n&&!t){return}else if(e&&"line"in e&&"column"in e&&r&&"line"in r&&"column"in r&&e.line>0&&e.column>=0&&r.line>0&&r.column>=0&&n){return}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:r,name:t}))}};SourceMapGenerator.prototype._serializeMappings=function SourceMapGenerator_serializeMappings(){var e=0;var r=1;var n=0;var i=0;var a=0;var u=0;var s="";var l;var c;var p;var f;var g=this._mappings.toArray();for(var d=0,h=g.length;d0){if(!o.compareByGeneratedPositionsInflated(c,g[d-1])){continue}l+=","}}l+=t.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);l+=t.encode(f-u);u=f;l+=t.encode(c.originalLine-1-i);i=c.originalLine-1;l+=t.encode(c.originalColumn-n);n=c.originalColumn;if(c.name!=null){p=this._names.indexOf(c.name);l+=t.encode(p-a);a=p}}s+=l}return s};SourceMapGenerator.prototype._generateSourcesContent=function SourceMapGenerator_generateSourcesContent(e,r){return e.map((function(e){if(!this._sourcesContents){return null}if(r!=null){e=o.relative(r,e)}var n=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null}),this)};SourceMapGenerator.prototype.toJSON=function SourceMapGenerator_toJSON(){var e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e};SourceMapGenerator.prototype.toString=function SourceMapGenerator_toString(){return JSON.stringify(this.toJSON())};r.x=SourceMapGenerator},565:(e,r,n)=>{var t;var o=n(163).x;var i=n(297);var a=/(\r?\n)/;var u=10;var s="$$$isSourceNode$$$";function SourceNode(e,r,n,t,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=r==null?null:r;this.source=n==null?null:n;this.name=o==null?null:o;this[s]=true;if(t!=null)this.add(t)}SourceNode.fromStringWithSourceMap=function SourceNode_fromStringWithSourceMap(e,r,n){var t=new SourceNode;var o=e.split(a);var u=0;var shiftNextLine=function(){var e=getNextLine();var r=getNextLine()||"";return e+r;function getNextLine(){return u=0;r--){this.prepend(e[r])}}else if(e[s]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this};SourceNode.prototype.walk=function SourceNode_walk(e){var r;for(var n=0,t=this.children.length;n0){r=[];for(n=0;n{function getArg(e,r,n){if(r in e){return e[r]}else if(arguments.length===3){return n}else{throw new Error('"'+r+'" is a required argument.')}}r.getArg=getArg;var n=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;var t=/^data:.+\,.+$/;function urlParse(e){var r=e.match(n);if(!r){return null}return{scheme:r[1],auth:r[2],host:r[3],port:r[4],path:r[5]}}r.urlParse=urlParse;function urlGenerate(e){var r="";if(e.scheme){r+=e.scheme+":"}r+="//";if(e.auth){r+=e.auth+"@"}if(e.host){r+=e.host}if(e.port){r+=":"+e.port}if(e.path){r+=e.path}return r}r.urlGenerate=urlGenerate;function normalize(e){var n=e;var t=urlParse(e);if(t){if(!t.path){return e}n=t.path}var o=r.isAbsolute(n);var i=n.split(/\/+/);for(var a,u=0,s=i.length-1;s>=0;s--){a=i[s];if(a==="."){i.splice(s,1)}else if(a===".."){u++}else if(u>0){if(a===""){i.splice(s+1,u);u=0}else{i.splice(s,2);u--}}}n=i.join("/");if(n===""){n=o?"/":"."}if(t){t.path=n;return urlGenerate(t)}return n}r.normalize=normalize;function join(e,r){if(e===""){e="."}if(r===""){r="."}var n=urlParse(r);var o=urlParse(e);if(o){e=o.path||"/"}if(n&&!n.scheme){if(o){n.scheme=o.scheme}return urlGenerate(n)}if(n||r.match(t)){return r}if(o&&!o.host&&!o.path){o.host=r;return urlGenerate(o)}var i=r.charAt(0)==="/"?r:normalize(e.replace(/\/+$/,"")+"/"+r);if(o){o.path=i;return urlGenerate(o)}return i}r.join=join;r.isAbsolute=function(e){return e.charAt(0)==="/"||n.test(e)};function relative(e,r){if(e===""){e="."}e=e.replace(/\/$/,"");var n=0;while(r.indexOf(e+"/")!==0){var t=e.lastIndexOf("/");if(t<0){return r}e=e.slice(0,t);if(e.match(/^([^\/]+:\/)?\/*$/)){return r}++n}return Array(n+1).join("../")+r.substr(e.length+1)}r.relative=relative;var o=function(){var e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}r.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}r.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}var r=e.length;if(r<9){return false}if(e.charCodeAt(r-1)!==95||e.charCodeAt(r-2)!==95||e.charCodeAt(r-3)!==111||e.charCodeAt(r-4)!==116||e.charCodeAt(r-5)!==111||e.charCodeAt(r-6)!==114||e.charCodeAt(r-7)!==112||e.charCodeAt(r-8)!==95||e.charCodeAt(r-9)!==95){return false}for(var n=r-10;n>=0;n--){if(e.charCodeAt(n)!==36){return false}}return true}function compareByOriginalPositions(e,r,n){var t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0||n){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0){return t}t=e.generatedLine-r.generatedLine;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByOriginalPositions=compareByOriginalPositions;function compareByGeneratedPositionsDeflated(e,r,n){var t=e.generatedLine-r.generatedLine;if(t!==0){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0||n){return t}t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsDeflated=compareByGeneratedPositionsDeflated;function strcmp(e,r){if(e===r){return 0}if(e===null){return 1}if(r===null){return-1}if(e>r){return 1}return-1}function compareByGeneratedPositionsInflated(e,r){var n=e.generatedLine-r.generatedLine;if(n!==0){return n}n=e.generatedColumn-r.generatedColumn;if(n!==0){return n}n=strcmp(e.source,r.source);if(n!==0){return n}n=e.originalLine-r.originalLine;if(n!==0){return n}n=e.originalColumn-r.originalColumn;if(n!==0){return n}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}r.parseSourceMapInput=parseSourceMapInput;function computeSourceURL(e,r,n){r=r||"";if(e){if(e[e.length-1]!=="/"&&r[0]!=="/"){e+="/"}r=e+r}if(n){var t=urlParse(n);if(!t){throw new Error("sourceMapURL could not be parsed")}if(t.path){var o=t.path.lastIndexOf("/");if(o>=0){t.path=t.path.substring(0,o+1)}}r=join(urlGenerate(t),r)}return normalize(r)}r.computeSourceURL=computeSourceURL},927:(e,r,n)=>{n(163).x;r.SourceMapConsumer=n(684).SourceMapConsumer;n(565)},896:e=>{"use strict";e.exports=require("fs")},928:e=>{"use strict";e.exports=require("path")}};var r={};function __webpack_require__(n){var t=r[n];if(t!==undefined){return t.exports}var o=r[n]={id:n,loaded:false,exports:{}};var i=true;try{e[n](o,o.exports,__webpack_require__);i=false}finally{if(i)delete r[n]}o.loaded=true;return o.exports}(()=>{__webpack_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __webpack_require__!=="undefined")__webpack_require__.ab=__dirname+"/";var n={};__webpack_require__(599).install();module.exports=n})(); \ No newline at end of file diff --git a/dist/src/action.d.ts b/dist/src/action.d.ts deleted file mode 100644 index 235789d..0000000 --- a/dist/src/action.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=action.d.ts.map \ No newline at end of file diff --git a/dist/src/action.js b/dist/src/action.js deleted file mode 100644 index 906ce2b..0000000 --- a/dist/src/action.js +++ /dev/null @@ -1,97 +0,0 @@ -import * as core from '@actions/core'; -import * as github from '@actions/github'; -import { PRAnalyzerAgent } from './agents/pr-analyzer-agent.js'; -async function run() { - try { - const apiKey = process.env.ANTHROPIC_API_KEY; - const ghToken = process.env.GITHUB_TOKEN; - if (!apiKey) { - core.setFailed('ANTHROPIC_API_KEY environment variable is required'); - return; - } - if (!ghToken) { - core.setFailed('GITHUB_TOKEN environment variable is required'); - return; - } - const { context } = github; - const { pull_request: pr, repository } = context.payload; - if (!pr) { - core.setFailed('This action can only be run on pull request events'); - return; - } - core.info(`Analyzing PR #${pr.number} in ${repository?.full_name}`); - const diff = await getPRDiffs(context, ghToken); - if (!diff) { - core.warning('No changes found in the pull request'); - return; - } - if (!repository) { - core.setFailed('Repository information not available'); - return; - } - core.info('Running LangChain agent analysis...'); - const agent = new PRAnalyzerAgent(apiKey, 'claude-sonnet-4-5-20250929'); - const result = await agent.analyze(diff, pr.title); - let summary = ''; - if (result.summary) { - summary += `### Summary\n${result.summary}\n\n`; - } - if (result.overallRisks.length > 0) { - summary += `### Potential Risks\n`; - result.overallRisks.forEach((risk) => { - summary += `- ${risk}\n`; - }); - summary += '\n'; - } - else { - summary += `### Potential Risks\nNone\n\n`; - } - summary += `### Complexity: ${result.overallComplexity}/5\n`; - if (result.recommendations && result.recommendations.length > 0) { - summary += `\n### Recommendations\n`; - result.recommendations.forEach((rec) => { - summary += `- ${rec}\n`; - }); - } - await postComment(pr.number, summary, repository, ghToken); - core.info('Analysis complete!'); - } - catch (error) { - core.setFailed(`Action failed with error: ${error}`); - } -} -async function getPRDiffs(context, ghToken) { - try { - const { pull_request: pr, repository } = context.payload; - const octokit = github.getOctokit(ghToken); - const { data: files } = await octokit.rest.pulls.listFiles({ - owner: repository.owner.login, - repo: repository.name, - pull_number: pr.number - }); - return files.map((f) => `--- ${f.filename}\n${f.patch}`).join('\n'); - } - catch (error) { - core.error('Error fetching PR diff:'); - core.error(String(error)); - throw new Error('Failed to fetch PR diff'); - } -} -async function postComment(prNumber, summary, repository, ghToken) { - try { - const octokit = github.getOctokit(ghToken); - await octokit.rest.issues.createComment({ - owner: repository.owner.login, - repo: repository.name, - issue_number: prNumber, - body: `## 🤖 AI Analysis (PR Agent by TechDebtGPT)\n\n${summary}` - }); - } - catch (error) { - core.error('Error posting comment:'); - core.error(String(error)); - throw new Error('Failed to post comment'); - } -} -run(); -//# sourceMappingURL=action.js.map \ No newline at end of file diff --git a/dist/src/action.js.map b/dist/src/action.js.map deleted file mode 100644 index 5a31f25..0000000 --- a/dist/src/action.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"action.js","sourceRoot":"","sources":["../../src/action.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/agents/base-pr-agent-workflow.d.ts b/dist/src/agents/base-pr-agent-workflow.d.ts deleted file mode 100644 index 37de32b..0000000 --- a/dist/src/agents/base-pr-agent-workflow.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MemorySaver } from '@langchain/langgraph'; -import { ChatAnthropic } from '@langchain/anthropic'; -import { AgentContext, AgentResult, FileAnalysis, AgentExecutionOptions } from '../types/agent.types.js'; -export declare const PRAgentState: import("@langchain/langgraph").AnnotationRoot<{ - context: import("@langchain/langgraph").BinaryOperatorAggregate; - iteration: import("@langchain/langgraph").BinaryOperatorAggregate; - fileAnalyses: import("@langchain/langgraph").BinaryOperatorAggregate, Map>; - currentSummary: import("@langchain/langgraph").BinaryOperatorAggregate; - currentRisks: import("@langchain/langgraph").BinaryOperatorAggregate; - currentComplexity: import("@langchain/langgraph").BinaryOperatorAggregate; - clarityScore: import("@langchain/langgraph").BinaryOperatorAggregate; - missingInformation: import("@langchain/langgraph").BinaryOperatorAggregate; - recommendations: import("@langchain/langgraph").BinaryOperatorAggregate; - insights: import("@langchain/langgraph").BinaryOperatorAggregate; - reasoning: import("@langchain/langgraph").BinaryOperatorAggregate; - totalInputTokens: import("@langchain/langgraph").BinaryOperatorAggregate; - totalOutputTokens: import("@langchain/langgraph").BinaryOperatorAggregate; -}>; -export interface PRAgentWorkflowConfig { - maxIterations: number; - clarityThreshold: number; - skipSelfRefinement?: boolean; -} -export declare abstract class BasePRAgentWorkflow { - protected model: ChatAnthropic; - protected workflow: ReturnType; - protected checkpointer: MemorySaver; - protected tools: any[]; - constructor(apiKey: string, modelName?: string); - private buildWorkflow; - execute(context: AgentContext, options?: AgentExecutionOptions): Promise; - private executeFastPath; - private analyzeFilesNode; - private detectRisksNode; - private calculateComplexityNode; - private generateSummaryNode; - private evaluateQualityNode; - private refineAnalysisNode; - private finalizeNode; - private shouldRefine; -} -//# sourceMappingURL=base-pr-agent-workflow.d.ts.map \ No newline at end of file diff --git a/dist/src/agents/base-pr-agent-workflow.js b/dist/src/agents/base-pr-agent-workflow.js deleted file mode 100644 index 7daa3d5..0000000 --- a/dist/src/agents/base-pr-agent-workflow.js +++ /dev/null @@ -1,318 +0,0 @@ -import { StateGraph, Annotation, END } from '@langchain/langgraph'; -import { MemorySaver } from '@langchain/langgraph'; -import { ChatAnthropic } from '@langchain/anthropic'; -import { parseDiff, createFileAnalyzerTool, createRiskDetectorTool, createComplexityScorerTool, createSummaryGeneratorTool, } from '../tools/pr-analysis-tools.js'; -export const PRAgentState = Annotation.Root({ - context: Annotation({ - reducer: (_, update) => update, - }), - iteration: Annotation({ - reducer: (_, update) => update, - default: () => 0, - }), - fileAnalyses: Annotation({ - reducer: (_, update) => update, - default: () => new Map(), - }), - currentSummary: Annotation({ - reducer: (_, update) => update, - default: () => '', - }), - currentRisks: Annotation({ - reducer: (_, update) => update, - default: () => [], - }), - currentComplexity: Annotation({ - reducer: (_, update) => update, - default: () => 1, - }), - clarityScore: Annotation({ - reducer: (_, update) => update, - default: () => 0, - }), - missingInformation: Annotation({ - reducer: (_, update) => update, - default: () => [], - }), - recommendations: Annotation({ - reducer: (_, update) => update, - default: () => [], - }), - insights: Annotation({ - reducer: (current, update) => [...current, ...update], - default: () => [], - }), - reasoning: Annotation({ - reducer: (current, update) => [...current, ...update], - default: () => [], - }), - totalInputTokens: Annotation({ - reducer: (current, update) => current + update, - default: () => 0, - }), - totalOutputTokens: Annotation({ - reducer: (current, update) => current + update, - default: () => 0, - }), -}); -export class BasePRAgentWorkflow { - model; - workflow; - checkpointer = new MemorySaver(); - tools; - constructor(apiKey, modelName = 'claude-sonnet-4-5-20250929') { - this.model = new ChatAnthropic({ - apiKey, - modelName, - temperature: 0.2, - maxTokens: 2000, - }); - this.tools = [ - createFileAnalyzerTool(), - createRiskDetectorTool(), - createComplexityScorerTool(), - createSummaryGeneratorTool(), - ]; - this.workflow = this.buildWorkflow(); - } - buildWorkflow() { - const graph = new StateGraph(PRAgentState); - graph.addNode('analyzeFiles', this.analyzeFilesNode.bind(this)); - graph.addNode('detectRisks', this.detectRisksNode.bind(this)); - graph.addNode('calculateComplexity', this.calculateComplexityNode.bind(this)); - graph.addNode('generateSummary', this.generateSummaryNode.bind(this)); - graph.addNode('evaluateQuality', this.evaluateQualityNode.bind(this)); - graph.addNode('refineAnalysis', this.refineAnalysisNode.bind(this)); - graph.addNode('finalize', this.finalizeNode.bind(this)); - const entryPoint = 'analyzeFiles'; - graph.setEntryPoint(entryPoint); - graph.addEdge(entryPoint, 'detectRisks'); - graph.addEdge('detectRisks', 'calculateComplexity'); - graph.addEdge('calculateComplexity', 'generateSummary'); - graph.addEdge('generateSummary', 'evaluateQuality'); - graph.addConditionalEdges('evaluateQuality', this.shouldRefine.bind(this), { - refine: 'refineAnalysis', - finalize: 'finalize', - }); - graph.addEdge('refineAnalysis', 'evaluateQuality'); - graph.addEdge('finalize', END); - return graph.compile({ checkpointer: this.checkpointer }); - } - async execute(context, options) { - const startTime = Date.now(); - if (options?.skipSelfRefinement) { - return this.executeFastPath(context, startTime); - } - const config = { - maxIterations: 3, - clarityThreshold: 80, - skipSelfRefinement: false, - }; - const initialState = { - context, - iteration: 0, - fileAnalyses: new Map(), - currentSummary: '', - currentRisks: [], - currentComplexity: 1, - clarityScore: 0, - missingInformation: [], - recommendations: [], - insights: [], - reasoning: [], - totalInputTokens: 0, - totalOutputTokens: 0, - }; - const workflowConfig = { - configurable: { - thread_id: `pr-agent-${Date.now()}`, - maxIterations: config.maxIterations, - clarityThreshold: config.clarityThreshold, - }, - recursionLimit: 50, - }; - let finalState = initialState; - let totalInputTokens = 0; - let totalOutputTokens = 0; - try { - for await (const state of await this.workflow.stream(initialState, workflowConfig)) { - const nodeNames = Object.keys(state); - if (nodeNames.length > 0) { - const lastNodeName = nodeNames[nodeNames.length - 1]; - finalState = state[lastNodeName] || finalState; - const stateAny = finalState; - if (stateAny.totalInputTokens !== undefined) { - totalInputTokens = stateAny.totalInputTokens; - } - if (stateAny.totalOutputTokens !== undefined) { - totalOutputTokens = stateAny.totalOutputTokens; - } - } - } - } - catch (error) { - console.error('Workflow execution error:', error); - throw error; - } - const executionTime = Date.now() - startTime; - return { - summary: finalState.currentSummary, - fileAnalyses: finalState.fileAnalyses, - overallComplexity: finalState.currentComplexity, - overallRisks: finalState.currentRisks, - recommendations: finalState.recommendations, - insights: finalState.insights, - reasoning: finalState.reasoning, - provider: 'anthropic', - model: this.model.modelName, - totalTokensUsed: totalInputTokens + totalOutputTokens, - executionTime, - mode: context.mode, - }; - } - async executeFastPath(context, startTime) { - const files = parseDiff(context.diff); - const fileAnalyses = new Map(); - for (const file of files.slice(0, 20)) { - const analysis = { - path: file.path, - summary: `Modified ${file.additions} lines, deleted ${file.deletions} lines`, - risks: [], - complexity: Math.min(5, Math.floor((file.additions + file.deletions) / 50) + 1), - changes: { - additions: file.additions, - deletions: file.deletions, - }, - recommendations: [], - }; - fileAnalyses.set(file.path, analysis); - } - const complexities = Array.from(fileAnalyses.values()).map(f => f.complexity); - const overallComplexity = complexities.length > 0 - ? Math.round(complexities.reduce((a, b) => a + b, 0) / complexities.length) - : 1; - const executionTime = Date.now() - startTime; - return { - summary: `Analyzed ${files.length} files with ${files.reduce((sum, f) => sum + f.additions, 0)} additions and ${files.reduce((sum, f) => sum + f.deletions, 0)} deletions`, - fileAnalyses, - overallComplexity, - overallRisks: [], - recommendations: ['Fast path analysis - run with --agent for detailed analysis'], - insights: [], - reasoning: ['Fast path: Self-refinement skipped for speed'], - provider: 'anthropic', - model: this.model.modelName, - totalTokensUsed: 0, - executionTime, - mode: context.mode, - }; - } - async analyzeFilesNode(state) { - const { context } = state; - const files = parseDiff(context.diff); - console.log(`🔍 Analyzing ${files.length} files...`); - const fileAnalyses = new Map(); - for (const file of files.slice(0, 20)) { - const analysis = { - path: file.path, - summary: `${file.status || 'M'}: +${file.additions} -${file.deletions}`, - risks: [], - complexity: Math.min(5, Math.floor((file.additions + file.deletions) / 50) + 1), - changes: { - additions: file.additions, - deletions: file.deletions, - }, - recommendations: [], - }; - fileAnalyses.set(file.path, analysis); - } - return { - ...state, - fileAnalyses, - insights: [`Analyzed ${files.length} files`], - }; - } - async detectRisksNode(state) { - const { context, fileAnalyses } = state; - console.log('⚠️ Detecting risks...'); - const risks = []; - if (context.diff.includes('password') || context.diff.includes('secret')) { - risks.push('Potential credentials in diff'); - } - if (fileAnalyses.size > 15) { - risks.push('Large change set - difficult to review'); - } - return { - ...state, - currentRisks: risks, - insights: [`Identified ${risks.length} potential risks`], - }; - } - async calculateComplexityNode(state) { - const { fileAnalyses } = state; - console.log('📊 Calculating complexity...'); - const complexities = Array.from(fileAnalyses.values()).map(f => f.complexity); - const avgComplexity = complexities.length > 0 - ? complexities.reduce((a, b) => a + b, 0) / complexities.length - : 1; - return { - ...state, - currentComplexity: Math.round(avgComplexity), - }; - } - async generateSummaryNode(state) { - const { context, fileAnalyses, currentRisks, currentComplexity } = state; - console.log('📝 Generating summary...'); - const totalFiles = fileAnalyses.size; - const totalAdditions = Array.from(fileAnalyses.values()).reduce((sum, f) => sum + f.changes.additions, 0); - const totalDeletions = Array.from(fileAnalyses.values()).reduce((sum, f) => sum + f.changes.deletions, 0); - const summary = `PR Analysis Summary: -- Files changed: ${totalFiles} -- Additions: ${totalAdditions} -- Deletions: ${totalDeletions} -- Overall complexity: ${currentComplexity}/5 -- Risks identified: ${currentRisks.length} - -${context.title ? `Title: ${context.title}` : ''}`; - return { - ...state, - currentSummary: summary, - }; - } - async evaluateQualityNode(state) { - const { iteration } = state; - console.log(`🔍 Evaluating quality (iteration ${iteration + 1})...`); - const clarityScore = 85; - return { - ...state, - clarityScore, - iteration: iteration + 1, - }; - } - async refineAnalysisNode(state) { - console.log('🔄 Refining analysis...'); - return { - ...state, - recommendations: ['Consider breaking into smaller PRs', 'Add more test coverage'], - }; - } - async finalizeNode(state) { - console.log('✨ Finalizing analysis...'); - return state; - } - shouldRefine(state) { - const maxIterations = 3; - const clarityThreshold = 80; - if (state.iteration >= maxIterations) { - console.log(`⏹️ Stopping: Max iterations (${maxIterations}) reached`); - return 'finalize'; - } - if (state.clarityScore >= clarityThreshold) { - console.log(`✅ Stopping: Clarity threshold (${clarityThreshold}) achieved`); - return 'finalize'; - } - console.log(`🔄 Continuing: Iteration ${state.iteration}, clarity ${state.clarityScore}`); - return 'refine'; - } -} -//# sourceMappingURL=base-pr-agent-workflow.js.map \ No newline at end of file diff --git a/dist/src/agents/base-pr-agent-workflow.js.map b/dist/src/agents/base-pr-agent-workflow.js.map deleted file mode 100644 index d919e82..0000000 --- a/dist/src/agents/base-pr-agent-workflow.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"base-pr-agent-workflow.js","sourceRoot":"","sources":["../../../src/agents/base-pr-agent-workflow.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/agents/index.d.ts b/dist/src/agents/index.d.ts deleted file mode 100644 index 5d1664a..0000000 --- a/dist/src/agents/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { BasePRAgentWorkflow, PRAgentState, PRAgentWorkflowConfig } from './base-pr-agent-workflow.js'; -export { PRAnalyzerAgent, createPRAnalyzerAgent } from './pr-analyzer-agent.js'; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/src/agents/index.js b/dist/src/agents/index.js deleted file mode 100644 index 96cf812..0000000 --- a/dist/src/agents/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export { BasePRAgentWorkflow, PRAgentState } from './base-pr-agent-workflow.js'; -export { PRAnalyzerAgent, createPRAnalyzerAgent } from './pr-analyzer-agent.js'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/src/agents/index.js.map b/dist/src/agents/index.js.map deleted file mode 100644 index f590a42..0000000 --- a/dist/src/agents/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/agents/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAyB,MAAM,6BAA6B,CAAC;AACvG,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC"} \ No newline at end of file diff --git a/dist/src/agents/pr-analyzer-agent.d.ts b/dist/src/agents/pr-analyzer-agent.d.ts deleted file mode 100644 index 1a1d8cb..0000000 --- a/dist/src/agents/pr-analyzer-agent.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { BasePRAgentWorkflow } from './base-pr-agent-workflow.js'; -import { AgentContext, AgentResult, AgentMetadata, AnalysisMode } from '../types/agent.types.js'; -export declare class PRAnalyzerAgent extends BasePRAgentWorkflow { - constructor(apiKey: string, modelName?: string); - getMetadata(): AgentMetadata; - analyze(diff: string, title?: string, mode?: AnalysisMode): Promise; - quickAnalyze(diff: string, title?: string): Promise; - analyzeFiles(diff: string, filePaths: string[]): Promise; - canExecute(context: AgentContext): Promise; - estimateTokens(context: AgentContext): Promise; -} -export declare function createPRAnalyzerAgent(apiKey: string, modelName?: string): PRAnalyzerAgent; -//# sourceMappingURL=pr-analyzer-agent.d.ts.map \ No newline at end of file diff --git a/dist/src/agents/pr-analyzer-agent.js b/dist/src/agents/pr-analyzer-agent.js deleted file mode 100644 index fc90471..0000000 --- a/dist/src/agents/pr-analyzer-agent.js +++ /dev/null @@ -1,77 +0,0 @@ -import { BasePRAgentWorkflow } from './base-pr-agent-workflow.js'; -import { parseDiff } from '../tools/pr-analysis-tools.js'; -export class PRAnalyzerAgent extends BasePRAgentWorkflow { - constructor(apiKey, modelName = 'claude-sonnet-4-5-20250929') { - super(apiKey, modelName); - } - getMetadata() { - return { - name: 'pr-analyzer', - version: '2.0.0', - description: 'AI-powered pull request analyzer using LangChain agent workflow', - capabilities: [ - 'file-level analysis', - 'risk detection', - 'complexity scoring', - 'intelligent recommendations', - 'self-refinement workflow', - ], - }; - } - async analyze(diff, title, mode) { - const files = parseDiff(diff); - const context = { - diff, - title, - files, - tokenBudget: 100000, - maxCost: 5.0, - mode: mode || { summary: true, risks: true, complexity: true }, - }; - const result = await this.execute(context, { - skipSelfRefinement: files.length < 5 || diff.length < 10000, - }); - return result; - } - async quickAnalyze(diff, title) { - const files = parseDiff(diff); - const context = { - diff, - title, - files, - tokenBudget: 50000, - maxCost: 2.0, - mode: { summary: true, risks: true, complexity: true }, - }; - return this.execute(context, { - skipSelfRefinement: true, - }); - } - async analyzeFiles(diff, filePaths) { - const allFiles = parseDiff(diff); - const files = allFiles.filter(f => filePaths.includes(f.path)); - const context = { - diff, - files, - tokenBudget: 50000, - maxCost: 2.0, - mode: { summary: true, risks: true, complexity: true }, - }; - return this.execute(context, { - skipSelfRefinement: true, - }); - } - async canExecute(context) { - return context.files.length > 0 && context.diff.length > 0; - } - async estimateTokens(context) { - const baseTokens = 2000; - const diffTokens = Math.ceil(context.diff.length / 4); - const filesTokens = context.files.length * 100; - return baseTokens + diffTokens + filesTokens; - } -} -export function createPRAnalyzerAgent(apiKey, modelName) { - return new PRAnalyzerAgent(apiKey, modelName); -} -//# sourceMappingURL=pr-analyzer-agent.js.map \ No newline at end of file diff --git a/dist/src/agents/pr-analyzer-agent.js.map b/dist/src/agents/pr-analyzer-agent.js.map deleted file mode 100644 index 5ad4369..0000000 --- a/dist/src/agents/pr-analyzer-agent.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"pr-analyzer-agent.js","sourceRoot":"","sources":["../../../src/agents/pr-analyzer-agent.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/cli/commands/analyze.command.d.ts b/dist/src/cli/commands/analyze.command.d.ts deleted file mode 100644 index 81089de..0000000 --- a/dist/src/cli/commands/analyze.command.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -interface AnalyzeOptions { - diff?: string; - file?: string; - staged?: boolean; - branch?: string; - title?: string; - provider?: string; - model?: string; - agent?: boolean; - summary?: boolean; - risks?: boolean; - complexity?: boolean; - full?: boolean; - verbose?: boolean; - maxCost?: number; -} -export declare function analyzePR(options?: AnalyzeOptions): Promise; -export {}; -//# sourceMappingURL=analyze.command.d.ts.map \ No newline at end of file diff --git a/dist/src/cli/commands/analyze.command.js b/dist/src/cli/commands/analyze.command.js deleted file mode 100644 index d19a7d7..0000000 --- a/dist/src/cli/commands/analyze.command.js +++ /dev/null @@ -1,302 +0,0 @@ -import * as fs from 'fs'; -import { execSync } from 'child_process'; -import chalk from 'chalk'; -import ora from 'ora'; -import { PRAnalyzerAgent } from '../../agents/pr-analyzer-agent.js'; -function shouldSkipFile(filePath) { - if (filePath.startsWith('dist/') || filePath.includes('/dist/')) { - return true; - } - if (filePath.startsWith('node_modules/') || filePath.includes('/node_modules/')) { - return true; - } - if (filePath.endsWith('.map') && filePath.includes('dist/')) { - return true; - } - if (filePath.includes('.d.ts') && filePath.includes('dist/')) { - return true; - } - return false; -} -async function getUntrackedFiles() { - try { - const output = execSync('git ls-files --others --exclude-standard', { - encoding: 'utf-8', - maxBuffer: 10 * 1024 * 1024, - }); - return output - .trim() - .split('\n') - .filter((f) => f.length > 0 && !shouldSkipFile(f)); - } - catch (error) { - return []; - } -} -async function getGitDiff(command) { - try { - let diff = ''; - const maxBuffer = 200 * 1024 * 1024; - if (!command || command === 'origin/main') { - try { - diff = execSync('git diff origin/main', { - encoding: 'utf-8', - maxBuffer, - }); - } - catch { - console.log(chalk.yellow('⚠️ origin/main not found, trying main branch...')); - diff = execSync('git diff main', { - encoding: 'utf-8', - maxBuffer, - }); - } - } - else if (command === 'staged') { - diff = execSync('git diff --staged', { - encoding: 'utf-8', - maxBuffer, - }); - } - else { - diff = execSync(`git diff ${command}`, { - encoding: 'utf-8', - maxBuffer, - }); - } - diff = diff.trim(); - const lines = diff.split('\n'); - const filteredLines = []; - let i = 0; - while (i < lines.length) { - const line = lines[i]; - if (line.startsWith('diff --git')) { - const match = line.match(/^diff --git a\/(.+?) b\/(.+?)$/); - if (match) { - const filePath = match[2] !== '/dev/null' ? match[2] : match[1]; - if (shouldSkipFile(filePath)) { - i++; - while (i < lines.length && !lines[i].startsWith('diff --git')) { - i++; - } - continue; - } - } - } - filteredLines.push(line); - i++; - } - diff = filteredLines.join('\n').trim(); - const untrackedFiles = await getUntrackedFiles(); - if (untrackedFiles.length > 0) { - for (const filePath of untrackedFiles) { - if (shouldSkipFile(filePath)) - continue; - try { - if (!fs.existsSync(filePath)) - continue; - const stats = fs.statSync(filePath); - if (stats.size > 5 * 1024 * 1024) - continue; - const content = fs.readFileSync(filePath, 'utf-8'); - const lines = content.split('\n'); - const diffHeader = `diff --git a/dev/null b/${filePath}\nnew file mode 100644\nindex 0000000..1111111\n--- /dev/null\n+++ b/${filePath}\n@@ -0,0 +1,${lines.length} @@\n`; - let fileDiff = diffHeader; - for (const line of lines) { - fileDiff += `+${line}\n`; - } - diff += (diff ? '\n' : '') + fileDiff; - } - catch (err) { - try { - if (fs.existsSync(filePath)) { - const stats = fs.statSync(filePath); - diff += (diff ? '\n' : '') + `diff --git a/dev/null b/${filePath}\nnew file mode 100644\nBinary file (${(stats.size / 1024).toFixed(0)}KB)\n`; - } - } - catch (statErr) { - continue; - } - } - } - } - if (!diff.trim() && untrackedFiles.length === 0) { - throw new Error('No changes detected'); - } - return diff || ''; - } - catch (error) { - console.error(chalk.red.bold('❌ Error getting git diff:'), error); - console.error(chalk.yellow('💡 Make sure you have a git repository with changes to analyze.')); - process.exit(1); - } -} -async function getPRTitle() { - try { - const title = execSync('git log -1 --pretty=%B', { encoding: 'utf-8' }).trim(); - return title; - } - catch (error) { - return undefined; - } -} -function estimateDiffSize(diff) { - return Math.ceil(diff.length / 4); -} -export async function analyzePR(options = {}) { - const spinner = ora('Initializing PR analysis...').start(); - try { - const apiKey = process.env.ANTHROPIC_API_KEY; - if (!apiKey) { - spinner.fail('ANTHROPIC_API_KEY environment variable is not set'); - console.error(chalk.yellow('💡 Please set it with: export ANTHROPIC_API_KEY="your-api-key"')); - process.exit(1); - } - const mode = { - summary: options.summary || options.full || false, - risks: options.risks || options.full || false, - complexity: options.complexity || options.full || false, - }; - if (!mode.summary && !mode.risks && !mode.complexity) { - mode.summary = true; - mode.risks = true; - mode.complexity = true; - } - spinner.text = 'Fetching diff...'; - let diff; - if (options.diff) { - diff = options.diff; - } - else if (options.file) { - diff = fs.readFileSync(options.file, 'utf-8'); - } - else if (options.staged) { - diff = await getGitDiff('staged'); - } - else if (options.branch) { - diff = await getGitDiff(options.branch); - } - else { - diff = await getGitDiff(); - } - if (!diff) { - spinner.fail('No diff found'); - process.exit(1); - } - const title = options.title || (await getPRTitle()); - const estimatedTokens = estimateDiffSize(diff); - spinner.succeed(`Diff ready: ~${estimatedTokens.toLocaleString()} tokens (${(diff.length / 1024).toFixed(0)}KB)`); - const useAgent = options.agent || diff.length > 50000; - if (useAgent) { - console.log(chalk.magenta.bold('\n🤖 Using Intelligent Agent Analysis (handling large diffs without chunking)...\n')); - console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')); - const model = options.model || 'claude-sonnet-4-5-20250929'; - const agent = new PRAnalyzerAgent(apiKey, model); - const result = await agent.analyze(diff, title, mode); - displayAgentResults(result, mode, options.verbose || false); - } - } - catch (error) { - spinner.fail('Analysis failed'); - if (error.message && error.message.includes('rate-limits')) { - console.error(chalk.red.bold('\n❌ Rate limit error: Your diff is too large for the API.')); - console.error(chalk.yellow('\n💡 Try using --agent flag for intelligent analysis of large diffs')); - } - else { - console.error(chalk.red('\nError:'), error instanceof Error ? error.message : error); - } - process.exit(1); - } -} -function displayAgentResults(result, mode, verbose) { - console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk.green.bold('\n✨ Agent Analysis Complete!\n')); - let cleanSummary = result.summary; - cleanSummary = cleanSummary.replace(/^#+\s*PR Analysis:?\s*/im, ''); - cleanSummary = cleanSummary.replace(/^##\s*Summary\s*/im, ''); - cleanSummary = cleanSummary.trim(); - if (mode.summary) { - console.log(chalk.cyan.bold('📋 Overall Summary\n')); - console.log(chalk.white(cleanSummary)); - console.log('\n'); - } - if (mode.risks && result.fileAnalyses.size > 0) { - const fileEntries = Array.from(result.fileAnalyses.entries()); - const filesWithRisks = fileEntries.filter(([_, analysis]) => analysis.risks.length > 0); - if (filesWithRisks.length > 0) { - console.log(chalk.yellow.bold(`⚠️ Risks by File (${filesWithRisks.length} files with risks)\n`)); - filesWithRisks.forEach(([path, analysis]) => { - console.log(chalk.cyan(` ${path}`)); - analysis.risks.forEach((risk, i) => { - const cleanRisk = risk.replace(/^\[File: [^\]]+\]\s*/, ''); - console.log(chalk.white(` ${i + 1}. ${cleanRisk}`)); - }); - console.log(''); - }); - } - else if (result.overallRisks.length > 0) { - console.log(chalk.yellow.bold('⚠️ Overall Risks\n')); - result.overallRisks.forEach((risk, i) => { - console.log(chalk.white(` ${i + 1}. ${risk}`)); - }); - console.log('\n'); - } - else { - console.log(chalk.yellow.bold('⚠️ Risks\n')); - console.log(chalk.white(' None identified\n\n')); - } - } - if (mode.complexity) { - console.log(chalk.magenta.bold(`📊 Overall Complexity: ${result.overallComplexity}/5\n`)); - } - if ((mode.summary || mode.complexity) && result.fileAnalyses.size > 0) { - console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk.cyan.bold(`\n📁 File Analysis (${result.fileAnalyses.size} files)\n`)); - const fileEntries = Array.from(result.fileAnalyses.entries()); - const highComplexity = fileEntries.filter(([_, analysis]) => analysis.complexity >= 4); - const mediumComplexity = fileEntries.filter(([_, analysis]) => analysis.complexity === 3); - if (highComplexity.length > 0) { - console.log(chalk.red.bold('🔴 High Complexity:\n')); - highComplexity.forEach(([path, analysis]) => { - console.log(chalk.white(` • ${path} (${analysis.complexity}/5)`)); - if (mode.risks && analysis.risks.length > 0) { - console.log(chalk.gray(` ${analysis.risks.length} risk${analysis.risks.length > 1 ? 's' : ''} found`)); - } - }); - console.log(''); - } - if (mediumComplexity.length > 0 && mediumComplexity.length <= 10) { - console.log(chalk.yellow.bold('🟡 Medium Complexity:\n')); - mediumComplexity.slice(0, 5).forEach(([path, analysis]) => { - console.log(chalk.white(` • ${path} (${analysis.complexity}/5)`)); - }); - if (mediumComplexity.length > 5) { - console.log(chalk.gray(` ... and ${mediumComplexity.length - 5} more`)); - } - console.log(''); - } - } - if (result.recommendations.length > 0) { - console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk.cyan.bold('\n💡 Recommendations\n')); - result.recommendations.forEach((rec, i) => { - console.log(chalk.white(` ${i + 1}. ${rec}`)); - }); - console.log('\n'); - } - if (verbose && result.reasoning.length > 0 && result.reasoning.length <= 5) { - console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk.cyan.bold('\n🤔 Analysis Strategy\n')); - result.reasoning.forEach((reason, i) => { - if (reason.includes('Strategy:') || i === 0) { - console.log(chalk.gray(` ${reason.substring(0, 150)}${reason.length > 150 ? '...' : ''}`)); - } - }); - console.log('\n'); - } - if (result.totalTokensUsed) { - console.log(chalk.gray(`\nTotal tokens used: ${result.totalTokensUsed.toLocaleString()}`)); - } - console.log(chalk.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')); -} -//# sourceMappingURL=analyze.command.js.map \ No newline at end of file diff --git a/dist/src/cli/commands/analyze.command.js.map b/dist/src/cli/commands/analyze.command.js.map deleted file mode 100644 index c3e762d..0000000 --- a/dist/src/cli/commands/analyze.command.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"analyze.command.js","sourceRoot":"","sources":["../../../../src/cli/commands/analyze.command.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/cli/commands/config.command.d.ts b/dist/src/cli/commands/config.command.d.ts deleted file mode 100644 index 35b3e0a..0000000 --- a/dist/src/cli/commands/config.command.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Command } from 'commander'; -export declare function registerConfigCommand(program: Command): void; -//# sourceMappingURL=config.command.d.ts.map \ No newline at end of file diff --git a/dist/src/cli/commands/config.command.js b/dist/src/cli/commands/config.command.js deleted file mode 100644 index 89784c2..0000000 --- a/dist/src/cli/commands/config.command.js +++ /dev/null @@ -1,368 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import inquirer from 'inquirer'; -import chalk from 'chalk'; -const CONFIG_FILE = '.pragent.config.json'; -const DEFAULT_CONFIG = { - apiKeys: { - anthropic: '', - openai: '', - google: '', - }, - ai: { - provider: 'claude', - model: 'claude-sonnet-4-5-20250929', - temperature: 0.2, - maxTokens: 2000, - }, - analysis: { - defaultMode: 'full', - maxCost: 5.0, - autoDetectAgent: true, - agentThreshold: 50000, - }, - git: { - defaultBranch: 'origin/main', - includeUntracked: true, - excludePatterns: [ - '**/node_modules/**', - '**/dist/**', - '**/build/**', - '**/.git/**', - '**/*.min.js', - '**/*.map', - '**/*.d.ts', - ], - }, - output: { - verbose: false, - showStrategy: true, - showRecommendations: true, - }, -}; -function findConfigPath() { - const rootConfig = path.join(process.cwd(), CONFIG_FILE); - if (fs.existsSync(rootConfig)) { - return rootConfig; - } - return null; -} -async function initializeConfig() { - console.log(chalk.cyan.bold('🚀 Welcome to PR Agent Setup!\n')); - const projectPath = process.cwd(); - const configPath = path.join(projectPath, CONFIG_FILE); - const existingConfig = fs.existsSync(configPath) - ? JSON.parse(fs.readFileSync(configPath, 'utf-8')) - : null; - if (existingConfig) { - console.log(chalk.yellow('⚠️ Found existing configuration:\n')); - console.log(` Provider: ${existingConfig.ai?.provider || 'Not set'}`); - console.log(` Model: ${existingConfig.ai?.model || 'Not set'}`); - console.log(` Default Mode: ${existingConfig.analysis?.defaultMode || 'full'}\n`); - const { shouldUpdate } = await inquirer.prompt([ - { - type: 'confirm', - name: 'shouldUpdate', - message: 'Update configuration?', - default: true, - }, - ]); - if (!shouldUpdate) { - console.log(chalk.gray('Setup cancelled.')); - return; - } - console.log(chalk.cyan('Updating configuration...\n')); - } - else { - console.log(chalk.gray(`Creating configuration in: ${CONFIG_FILE}\n`)); - } - const { provider } = await inquirer.prompt([ - { - type: 'list', - name: 'provider', - message: 'Select AI provider:', - choices: [ - { name: 'Anthropic Claude (Recommended)', value: 'claude' }, - { name: 'OpenAI GPT', value: 'openai' }, - { name: 'Google Gemini', value: 'google' }, - ], - default: 'claude', - }, - ]); - let modelChoices = []; - if (provider === 'claude') { - modelChoices = [ - { name: 'Claude Sonnet 4.5 (Recommended)', value: 'claude-sonnet-4-5-20250929' }, - { name: 'Claude Sonnet 3.5', value: 'claude-3-5-sonnet-20241022' }, - { name: 'Claude Opus', value: 'claude-3-opus-20240229' }, - ]; - } - else if (provider === 'openai') { - modelChoices = [ - { name: 'GPT-4 Turbo', value: 'gpt-4-turbo-preview' }, - { name: 'GPT-4', value: 'gpt-4' }, - { name: 'GPT-3.5 Turbo', value: 'gpt-3.5-turbo' }, - ]; - } - else if (provider === 'google') { - modelChoices = [ - { name: 'Gemini Pro', value: 'gemini-pro' }, - { name: 'Gemini Ultra', value: 'gemini-ultra' }, - ]; - } - const { model } = await inquirer.prompt([ - { - type: 'list', - name: 'model', - message: 'Select model:', - choices: modelChoices, - }, - ]); - const { apiKey, saveApiKey } = await inquirer.prompt([ - { - type: 'password', - name: 'apiKey', - message: `Enter ${provider.toUpperCase()} API key (or leave empty to use environment variable):`, - mask: '*', - }, - { - type: 'confirm', - name: 'saveApiKey', - message: 'Save API key to config file? (will be added to .gitignore)', - default: false, - when: (answers) => !!answers.apiKey, - }, - ]); - const { defaultMode, autoDetectAgent } = await inquirer.prompt([ - { - type: 'list', - name: 'defaultMode', - message: 'Default analysis mode:', - choices: [ - { name: 'Full (summary + risks + complexity)', value: 'full' }, - { name: 'Summary only', value: 'summary' }, - { name: 'Risks only', value: 'risks' }, - { name: 'Complexity only', value: 'complexity' }, - ], - default: 'full', - }, - { - type: 'confirm', - name: 'autoDetectAgent', - message: 'Auto-detect when to use intelligent agent for large diffs?', - default: true, - }, - ]); - const config = existingConfig - ? JSON.parse(JSON.stringify(existingConfig)) - : JSON.parse(JSON.stringify(DEFAULT_CONFIG)); - config.ai.provider = provider; - config.ai.model = model; - if (saveApiKey && apiKey) { - config.apiKeys[provider] = apiKey; - } - config.analysis.defaultMode = defaultMode; - config.analysis.autoDetectAgent = autoDetectAgent; - fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); - const isUpdate = !!existingConfig; - console.log(chalk.green(`\n✅ ${isUpdate ? 'Updated' : 'Created'} ${path.relative(process.cwd(), configPath)}`)); - if (saveApiKey && apiKey) { - const gitignorePath = path.join(process.cwd(), '.gitignore'); - let shouldAddGitignore = false; - if (fs.existsSync(gitignorePath)) { - const gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8'); - if (!gitignoreContent.includes('.pragent.config.json')) { - const { addToGitignore } = await inquirer.prompt([ - { - type: 'confirm', - name: 'addToGitignore', - message: 'Add .pragent.config.json to .gitignore? (recommended - contains API keys)', - default: true, - }, - ]); - shouldAddGitignore = addToGitignore; - } - } - if (shouldAddGitignore) { - fs.appendFileSync(gitignorePath, '\n# PR Agent configuration (contains API keys)\n.pragent.config.json\n'); - console.log(chalk.green('✅ Added .pragent.config.json to .gitignore')); - } - } - console.log(chalk.green('\n🎉 Setup complete!')); - console.log(chalk.cyan('\n📝 Configuration Summary:')); - console.log(` • Config file: ${path.relative(process.cwd(), configPath)}`); - console.log(` • AI Provider: ${config.ai.provider} (${config.ai.model})`); - console.log(` • Default Mode: ${config.analysis.defaultMode}`); - console.log(` • Auto Agent: ${config.analysis.autoDetectAgent ? 'Enabled' : 'Disabled'}`); - console.log(chalk.cyan('\n💡 Tips:')); - console.log(' • Change provider: pr-agent config --set ai.provider=openai'); - console.log(' • Change model: pr-agent config --set ai.model=gpt-4-turbo-preview'); - console.log(' • View settings: pr-agent config --list'); - console.log(chalk.cyan('\nNext steps:')); - console.log(' 1. Run: pr-agent analyze'); - console.log(' 2. Or: pr-agent analyze --staged'); - console.log(' 3. Or: pr-agent analyze --branch develop'); -} -function listConfig() { - const configPath = findConfigPath(); - if (!configPath) { - console.error(chalk.red(`❌ ${CONFIG_FILE} not found. Run: pr-agent config --init`)); - process.exit(1); - } - const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); - const maskedConfig = JSON.parse(JSON.stringify(config)); - if (maskedConfig.apiKeys) { - Object.keys(maskedConfig.apiKeys).forEach((key) => { - if (maskedConfig.apiKeys[key]) { - maskedConfig.apiKeys[key] = '***' + maskedConfig.apiKeys[key].slice(-4); - } - }); - } - console.log(chalk.cyan(`📋 Configuration (${path.relative(process.cwd(), configPath)}):\n`)); - console.log(JSON.stringify(maskedConfig, null, 2)); -} -function getConfigValue(key) { - const configPath = findConfigPath(); - if (!configPath) { - console.error(chalk.red(`❌ ${CONFIG_FILE} not found. Run: pr-agent config --init`)); - process.exit(1); - } - const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); - const keys = key.split('.'); - let value = config; - for (const k of keys) { - if (value && typeof value === 'object' && k in value) { - value = value[k]; - } - else { - console.error(chalk.red(`❌ Key not found: ${key}`)); - process.exit(1); - } - } - console.log(JSON.stringify(value, null, 2)); -} -function setConfigValue(keyValue) { - const configPath = findConfigPath(); - if (!configPath) { - console.error(chalk.red(`❌ ${CONFIG_FILE} not found. Run: pr-agent config --init`)); - process.exit(1); - } - const [key, ...valueParts] = keyValue.split('='); - const valueStr = valueParts.join('='); - if (!key || !valueStr) { - console.error(chalk.red('❌ Invalid format. Use: key=value (e.g., ai.temperature=0.5)')); - process.exit(1); - } - const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); - const keys = key.split('.'); - let current = config; - for (let i = 0; i < keys.length - 1; i++) { - const k = keys[i]; - if (!current[k] || typeof current[k] !== 'object') { - current[k] = {}; - } - current = current[k]; - } - let value; - try { - value = JSON.parse(valueStr); - } - catch { - value = valueStr; - } - current[keys[keys.length - 1]] = value; - fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); - console.log(chalk.green(`✅ Set ${key} = ${JSON.stringify(value)}`)); - console.log(chalk.gray(` in ${path.relative(process.cwd(), configPath)}`)); -} -function resetConfig() { - const configPath = findConfigPath(); - if (!configPath) { - console.error(chalk.red(`❌ ${CONFIG_FILE} not found. Run: pr-agent config --init`)); - process.exit(1); - } - fs.writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2)); - console.log(chalk.green(`✅ Reset ${path.relative(process.cwd(), configPath)} to defaults`)); -} -function validateConfig() { - const configPath = findConfigPath(); - if (!configPath) { - console.error(chalk.red(`❌ ${CONFIG_FILE} not found. Run: pr-agent config --init`)); - process.exit(1); - } - try { - const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); - const errors = []; - if (!config.ai || !config.ai.provider) { - errors.push('Missing ai.provider'); - } - if (!config.ai || !config.ai.model) { - errors.push('Missing ai.model'); - } - if (!config.apiKeys) { - errors.push('Missing apiKeys section'); - } - if (errors.length > 0) { - console.log(chalk.red('❌ Configuration validation failed:\n')); - errors.forEach(error => console.log(chalk.red(` • ${error}`))); - process.exit(1); - } - console.log(chalk.green('✅ Configuration is valid!')); - console.log(chalk.cyan('\n📋 Configuration Summary:')); - console.log(` • Provider: ${config.ai.provider}`); - console.log(` • Model: ${config.ai.model}`); - console.log(` • Default Mode: ${config.analysis?.defaultMode || 'full'}`); - console.log(` • API Key Set: ${config.apiKeys[config.ai.provider] ? 'Yes' : 'No (using env var)'}`); - } - catch (error) { - console.error(chalk.red('❌ Invalid JSON in configuration file')); - process.exit(1); - } -} -export function registerConfigCommand(program) { - program - .command('config') - .description('Manage PR Agent configuration') - .option('--init', 'Initialize configuration with interactive setup') - .option('--list', 'List all configuration values (API keys masked)') - .option('--get ', 'Get specific configuration value (e.g., ai.temperature)') - .option('--set ', 'Set configuration value (e.g., ai.temperature=0.5)') - .option('--reset', 'Reset configuration to defaults') - .option('--validate', 'Validate configuration file') - .action(async (options) => { - try { - if (options.init) { - await initializeConfig(); - } - else if (options.list) { - listConfig(); - } - else if (options.get) { - getConfigValue(options.get); - } - else if (options.set) { - setConfigValue(options.set); - } - else if (options.reset) { - resetConfig(); - } - else if (options.validate) { - validateConfig(); - } - else { - console.log(chalk.cyan('Usage:')); - console.log(' pr-agent config --init # Interactive setup'); - console.log(' pr-agent config --list # Show all settings'); - console.log(' pr-agent config --get ai.model # Get specific value'); - console.log(' pr-agent config --set ai.temperature=0.5 # Set value'); - console.log(' pr-agent config --validate # Validate config'); - console.log(' pr-agent config --reset # Reset to defaults'); - } - } - catch (error) { - console.error(chalk.red('❌ Error:'), error instanceof Error ? error.message : error); - process.exit(1); - } - }); -} -//# sourceMappingURL=config.command.js.map \ No newline at end of file diff --git a/dist/src/cli/commands/config.command.js.map b/dist/src/cli/commands/config.command.js.map deleted file mode 100644 index 2663f1c..0000000 --- a/dist/src/cli/commands/config.command.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"config.command.js","sourceRoot":"","sources":["../../../../src/cli/commands/config.command.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/cli/commands/help.command.d.ts b/dist/src/cli/commands/help.command.d.ts deleted file mode 100644 index 3aba8ac..0000000 --- a/dist/src/cli/commands/help.command.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Command } from 'commander'; -export declare function displayHelp(): void; -export declare function registerHelpCommand(program: Command): void; -//# sourceMappingURL=help.command.d.ts.map \ No newline at end of file diff --git a/dist/src/cli/commands/help.command.js b/dist/src/cli/commands/help.command.js deleted file mode 100644 index 73d6c51..0000000 --- a/dist/src/cli/commands/help.command.js +++ /dev/null @@ -1,157 +0,0 @@ -import chalk from 'chalk'; -export function displayHelp() { - console.log(chalk.bold.cyan('\n🤖 PR Agent - AI-Powered Pull Request Analyzer\n')); - console.log(chalk.dim('Analyze pull requests and code changes with AI to identify risks, complexity, and provide insights.\n')); - console.log(chalk.bold.yellow('📖 QUICK START\n')); - console.log(chalk.green(' 1. Setup:') + ' pr-agent config --init'); - console.log(chalk.green(' 2. Analyze:') + ' pr-agent analyze'); - console.log(chalk.green(' 3. Custom:') + ' pr-agent analyze --branch develop --full\n'); - console.log(chalk.bold.yellow('🚀 COMMANDS\n')); - console.log(chalk.bold(' analyze')); - console.log(' Analyze pull request changes with AI\n'); - console.log(chalk.dim(' Examples:')); - console.log(' pr-agent analyze # Analyze against origin/main'); - console.log(' pr-agent analyze --staged # Analyze staged changes'); - console.log(' pr-agent analyze --branch develop # Analyze against develop'); - console.log(' pr-agent analyze --file diff.txt # Analyze from file'); - console.log(' pr-agent analyze --full # Full analysis (all modes)'); - console.log(' pr-agent analyze --agent # Force intelligent agent\n'); - console.log(chalk.dim(' Analysis Modes:')); - console.log(' --summary Show summary only'); - console.log(' --risks Show risks only'); - console.log(' --complexity Show complexity only'); - console.log(' --full Show all (default)\n'); - console.log(chalk.dim(' Diff Sources:')); - console.log(' --staged Analyze staged changes (git diff --staged)'); - console.log(' --branch Analyze against specific branch'); - console.log(' --file Read diff from file'); - console.log(' --diff Provide diff directly\n'); - console.log(chalk.dim(' Advanced Options:')); - console.log(' --agent Force intelligent agent (recommended for large diffs)'); - console.log(' --provider AI provider: claude|openai|google'); - console.log(' --model Specific model to use'); - console.log(' --title PR title (auto-detected from git)'); - console.log(' --max-cost Maximum cost limit (default: $5.00)'); - console.log(' --verbose Enable verbose output\n'); - console.log(chalk.bold(' config')); - console.log(' Manage PR Agent configuration\n'); - console.log(chalk.dim(' Examples:')); - console.log(' pr-agent config --init # Interactive setup wizard'); - console.log(' pr-agent config --list # Show current configuration'); - console.log(' pr-agent config --validate # Validate configuration\n'); - console.log(chalk.dim(' Options:')); - console.log(' --init Run interactive configuration wizard'); - console.log(' --list Display current configuration'); - console.log(' --get Get specific value (e.g., ai.model)'); - console.log(' --set Set specific value (e.g., ai.temperature=0.5)'); - console.log(' --validate Validate configuration file'); - console.log(' --reset Reset configuration to defaults\n'); - console.log(chalk.bold(' help')); - console.log(' Display this comprehensive help information\n'); - console.log(chalk.bold.yellow('📊 ANALYSIS MODES\n')); - console.log(chalk.green(' Summary') + ' - Overview of changes, impact assessment, and key modifications'); - console.log(chalk.green(' Risks') + ' - Potential issues, security concerns, and breaking changes'); - console.log(chalk.green(' Complexity') + ' - Complexity score (1-5) and maintainability assessment'); - console.log(chalk.green(' Full') + ' - All of the above (default mode)\n'); - console.log(chalk.bold.yellow('🧠 INTELLIGENT AGENT\n')); - console.log(' The PR Agent automatically uses an intelligent agent for large diffs (>50KB).'); - console.log(' The agent provides:\n'); - console.log(' • ' + chalk.cyan('File-level analysis') + ' with individual risk and complexity scores'); - console.log(' • ' + chalk.cyan('Strategic reasoning') + ' about analysis approach'); - console.log(' • ' + chalk.cyan('Contextual recommendations') + ' based on changes'); - console.log(' • ' + chalk.cyan('No chunking required') + ' - handles large diffs intelligently\n'); - console.log(chalk.dim(' Force agent mode:') + ' pr-agent analyze --agent\n'); - console.log(chalk.bold.yellow('🔑 ENVIRONMENT VARIABLES\n')); - console.log(' API Keys:'); - console.log(' ANTHROPIC_API_KEY Anthropic Claude API key (required for Claude)'); - console.log(' OPENAI_API_KEY OpenAI GPT API key (required for OpenAI)'); - console.log(' GOOGLE_API_KEY Google Gemini API key (required for Gemini)\n'); - console.log(chalk.dim(' Note: API keys can also be stored in .pragent.config.json\n')); - console.log(chalk.bold.yellow('📝 CONFIGURATION FILE\n')); - console.log(' Location: ' + chalk.cyan('.pragent.config.json') + ' (root directory)'); - console.log(' Create: ' + chalk.cyan('pr-agent config --init\n')); - console.log(chalk.dim(' Example structure:')); - console.log(chalk.dim(` { - "ai": { - "provider": "claude", - "model": "claude-sonnet-4-5-20250929", - "temperature": 0.2, - "maxTokens": 2000 - }, - "apiKeys": { - "anthropic": "sk-ant-..." - }, - "analysis": { - "defaultMode": "full", - "maxCost": 5.0, - "autoDetectAgent": true - }, - "git": { - "defaultBranch": "origin/main", - "includeUntracked": true - } - }\n`)); - console.log(chalk.bold.yellow('🌐 SUPPORTED AI PROVIDERS\n')); - console.log(chalk.green(' Anthropic Claude') + ' (Recommended)'); - console.log(' • claude-sonnet-4-5-20250929 (default)'); - console.log(' • claude-3-5-sonnet-20241022'); - console.log(' • claude-3-opus-20240229\n'); - console.log(chalk.green(' OpenAI GPT')); - console.log(' • gpt-4-turbo-preview'); - console.log(' • gpt-4'); - console.log(' • gpt-3.5-turbo\n'); - console.log(chalk.green(' Google Gemini')); - console.log(' • gemini-pro'); - console.log(' • gemini-ultra\n'); - console.log(chalk.bold.yellow('💡 COMMON WORKFLOWS\n')); - console.log(chalk.bold(' First-time setup:')); - console.log(' 1. pr-agent config --init'); - console.log(' 2. pr-agent analyze\n'); - console.log(chalk.bold(' Quick PR review:')); - console.log(' pr-agent analyze --full\n'); - console.log(chalk.bold(' Review staged changes before commit:')); - console.log(' pr-agent analyze --staged\n'); - console.log(chalk.bold(' Compare feature branch:')); - console.log(' git checkout feature-branch'); - console.log(' pr-agent analyze --branch develop\n'); - console.log(chalk.bold(' Analyze diff from file:')); - console.log(' git diff > changes.diff'); - console.log(' pr-agent analyze --file changes.diff\n'); - console.log(chalk.bold(' Large PR analysis:')); - console.log(' pr-agent analyze --agent --verbose\n'); - console.log(chalk.bold(' Custom provider:')); - console.log(' pr-agent analyze --provider openai --model gpt-4-turbo-preview\n'); - console.log(chalk.bold.yellow('🔄 CI/CD INTEGRATION\n')); - console.log(chalk.bold(' GitHub Actions:')); - console.log(chalk.dim(' - name: Analyze PR')); - console.log(chalk.dim(' run: |')); - console.log(chalk.dim(' npm install -g pr-agent')); - console.log(chalk.dim(' pr-agent analyze --full')); - console.log(chalk.dim(' env:')); - console.log(chalk.dim(' ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}\n')); - console.log(chalk.bold(' GitLab CI:')); - console.log(chalk.dim(' analyze-pr:')); - console.log(chalk.dim(' script:')); - console.log(chalk.dim(' - npm install -g pr-agent')); - console.log(chalk.dim(' - pr-agent analyze --full\n')); - console.log(chalk.bold.yellow('✨ TIPS & BEST PRACTICES\n')); - console.log(' • Use ' + chalk.cyan('--agent') + ' for diffs larger than 50KB for better analysis'); - console.log(' • Set ' + chalk.cyan('--max-cost') + ' to control API spending on large PRs'); - console.log(' • Use ' + chalk.cyan('--staged') + ' to review changes before committing'); - console.log(' • Store API keys in ' + chalk.cyan('.pragent.config.json') + ' and add to .gitignore'); - console.log(' • Use ' + chalk.cyan('--verbose') + ' to see detailed reasoning and strategy'); - console.log(' • Configure ' + chalk.cyan('defaultMode') + ' in config for your team\'s workflow\n'); - console.log(chalk.dim('━'.repeat(80))); - console.log(chalk.dim(' For detailed help on a specific command: ') + chalk.cyan('pr-agent --help')); - console.log(chalk.dim(' Report issues: ') + chalk.cyan('https://github.com/your-org/pr-agent/issues')); - console.log(chalk.dim('━'.repeat(80) + '\n')); -} -export function registerHelpCommand(program) { - program - .command('help') - .description('Display comprehensive help information') - .action(() => { - displayHelp(); - }); -} -//# sourceMappingURL=help.command.js.map \ No newline at end of file diff --git a/dist/src/cli/commands/help.command.js.map b/dist/src/cli/commands/help.command.js.map deleted file mode 100644 index 308b6fb..0000000 --- a/dist/src/cli/commands/help.command.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"help.command.js","sourceRoot":"","sources":["../../../../src/cli/commands/help.command.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/cli/index.d.ts b/dist/src/cli/index.d.ts deleted file mode 100644 index dc1ec89..0000000 --- a/dist/src/cli/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node -export {}; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/src/cli/index.js b/dist/src/cli/index.js deleted file mode 100644 index ba81cff..0000000 --- a/dist/src/cli/index.js +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env node -import * as path from 'path'; -import * as fs from 'fs'; -import { Command } from 'commander'; -import { analyzePR } from './commands/analyze.command.js'; -import { registerConfigCommand } from './commands/config.command.js'; -import { registerHelpCommand } from './commands/help.command.js'; -const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../package.json'), 'utf-8')); -const program = new Command(); -program - .name('pr-agent') - .description('AI-powered pull request analyzer and code review assistant') - .version(packageJson.version); -program - .command('analyze') - .description('Analyze pull request changes with AI') - .option('--diff ', 'Provide diff text directly') - .option('--file ', 'Read diff from file') - .option('--staged', 'Analyze staged changes (git diff --staged)') - .option('--branch ', 'Analyze against specific branch') - .option('--title ', 'PR title (auto-detected from git)') - .option('--provider ', 'AI provider (claude|openai|google)', 'claude') - .option('--model ', 'Specific model to use') - .option('--agent', 'Force intelligent agent (recommended for large diffs)') - .option('--summary', 'Show summary only') - .option('--risks', 'Show risks only') - .option('--complexity', 'Show complexity only') - .option('--full', 'Show all modes (default)', true) - .option('--max-cost ', 'Maximum cost in dollars', '5.0') - .option('--verbose', 'Enable verbose output', false) - .action(analyzePR); -registerConfigCommand(program); -registerHelpCommand(program); -program.parse(); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/src/cli/index.js.map b/dist/src/cli/index.js.map deleted file mode 100644 index 8720f69..0000000 --- a/dist/src/cli/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGjE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,CAAC,EAAE,OAAO,CAAC,CACxE,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,4DAA4D,CAAC;KACzE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAGhC,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,eAAe,EAAE,4BAA4B,CAAC;KACrD,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;KAC9C,MAAM,CAAC,UAAU,EAAE,4CAA4C,CAAC;KAChE,MAAM,CAAC,iBAAiB,EAAE,iCAAiC,CAAC;KAC5D,MAAM,CAAC,gBAAgB,EAAE,mCAAmC,CAAC;KAC7D,MAAM,CAAC,uBAAuB,EAAE,oCAAoC,EAAE,QAAQ,CAAC;KAC/E,MAAM,CAAC,iBAAiB,EAAE,uBAAuB,CAAC;KAClD,MAAM,CAAC,SAAS,EAAE,uDAAuD,CAAC;KAC1E,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAAC;KACxC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC;KACpC,MAAM,CAAC,cAAc,EAAE,sBAAsB,CAAC;KAC9C,MAAM,CAAC,QAAQ,EAAE,0BAA0B,EAAE,IAAI,CAAC;KAClD,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,EAAE,KAAK,CAAC;KAChE,MAAM,CAAC,WAAW,EAAE,uBAAuB,EAAE,KAAK,CAAC;KACnD,MAAM,CAAC,SAAS,CAAC,CAAC;AAGrB,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAG/B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAG7B,OAAO,CAAC,KAAK,EAAE,CAAC"} \ No newline at end of file diff --git a/dist/src/cli/utils/config-loader.d.ts b/dist/src/cli/utils/config-loader.d.ts deleted file mode 100644 index da1353e..0000000 --- a/dist/src/cli/utils/config-loader.d.ts +++ /dev/null @@ -1,35 +0,0 @@ -export interface UserConfig { - apiKeys?: { - anthropic?: string; - openai?: string; - google?: string; - }; - ai?: { - provider?: string; - model?: string; - temperature?: number; - maxTokens?: number; - }; - analysis?: { - defaultMode?: string; - maxCost?: number; - autoDetectAgent?: boolean; - agentThreshold?: number; - }; - git?: { - defaultBranch?: string; - includeUntracked?: boolean; - excludePatterns?: string[]; - }; - output?: { - verbose?: boolean; - showStrategy?: boolean; - showRecommendations?: boolean; - }; -} -export declare function findConfigFile(): string | null; -export declare function loadUserConfig(verbose?: boolean): Promise; -export declare function checkConfiguration(): Promise; -export declare function getApiKey(provider: string, config?: UserConfig): string | undefined; -export declare function saveConfig(config: UserConfig, configPath?: string): void; -//# sourceMappingURL=config-loader.d.ts.map \ No newline at end of file diff --git a/dist/src/cli/utils/config-loader.js b/dist/src/cli/utils/config-loader.js deleted file mode 100644 index eb516da..0000000 --- a/dist/src/cli/utils/config-loader.js +++ /dev/null @@ -1,87 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import chalk from 'chalk'; -const CONFIG_FILE = '.pragent.config.json'; -export function findConfigFile() { - let currentDir = process.cwd(); - const root = path.parse(currentDir).root; - while (currentDir !== root) { - const configPath = path.join(currentDir, CONFIG_FILE); - if (fs.existsSync(configPath)) { - return configPath; - } - currentDir = path.dirname(currentDir); - } - const rootConfigPath = path.join(root, CONFIG_FILE); - if (fs.existsSync(rootConfigPath)) { - return rootConfigPath; - } - return null; -} -export async function loadUserConfig(verbose = false) { - const configPath = findConfigFile(); - if (!configPath) { - if (verbose) { - console.log(chalk.yellow('⚠️ No configuration file found')); - console.log(chalk.gray(' Run: pr-agent config --init')); - } - return {}; - } - try { - const configContent = fs.readFileSync(configPath, 'utf-8'); - const config = JSON.parse(configContent); - if (verbose) { - console.log(chalk.green(`✅ Loaded configuration from: ${path.relative(process.cwd(), configPath)}`)); - } - return config; - } - catch (error) { - if (verbose) { - console.error(chalk.red(`❌ Error loading configuration: ${error}`)); - } - return {}; - } -} -export async function checkConfiguration() { - const configPath = findConfigFile(); - if (!configPath) { - console.log(chalk.yellow('\n⚠️ No configuration found')); - console.log(chalk.gray(' Run: pr-agent config --init')); - console.log(chalk.gray(' Or set ANTHROPIC_API_KEY environment variable\n')); - return true; - } - try { - const config = await loadUserConfig(false); - if (!config.ai?.provider && !process.env.ANTHROPIC_API_KEY) { - console.log(chalk.yellow('\n⚠️ No AI provider configured')); - console.log(chalk.gray(' Run: pr-agent config --init\n')); - return true; - } - return true; - } - catch (error) { - console.error(chalk.red(`❌ Invalid configuration: ${error}`)); - return false; - } -} -export function getApiKey(provider, config) { - if (config?.apiKeys && config.apiKeys[provider]) { - return config.apiKeys[provider]; - } - const envVarMap = { - claude: 'ANTHROPIC_API_KEY', - anthropic: 'ANTHROPIC_API_KEY', - openai: 'OPENAI_API_KEY', - google: 'GOOGLE_API_KEY', - }; - const envVar = envVarMap[provider.toLowerCase()]; - if (envVar) { - return process.env[envVar]; - } - return undefined; -} -export function saveConfig(config, configPath) { - const targetPath = configPath || path.join(process.cwd(), CONFIG_FILE); - fs.writeFileSync(targetPath, JSON.stringify(config, null, 2), 'utf-8'); -} -//# sourceMappingURL=config-loader.js.map \ No newline at end of file diff --git a/dist/src/cli/utils/config-loader.js.map b/dist/src/cli/utils/config-loader.js.map deleted file mode 100644 index 3fcfd8c..0000000 --- a/dist/src/cli/utils/config-loader.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../../../src/cli/utils/config-loader.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/cli/utils/config-prompts.d.ts b/dist/src/cli/utils/config-prompts.d.ts deleted file mode 100644 index 4a6ed89..0000000 --- a/dist/src/cli/utils/config-prompts.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { UserConfig } from './config-loader.js'; -export interface PromptOptions { - includeApiKey?: boolean; - includeAnalysisPreferences?: boolean; - verbose?: boolean; -} -export interface PromptAnswers { - provider: string; - selectedModel: string; - apiKey?: string; - saveApiKey?: boolean; - defaultMode?: string; - autoDetectAgent?: boolean; -} -export declare function getExistingConfig(projectPath: string): UserConfig | null; -export declare function promptFullConfig(projectPath: string, options?: PromptOptions): Promise<{ - answers: PromptAnswers; - existingConfig: UserConfig | null; -}>; -export declare function promptProvider(defaultProvider?: string): Promise; -export declare function promptApiKey(provider: string): Promise; -export declare function promptConfirm(message: string, defaultValue?: boolean): Promise; -export declare function displayConfigSummary(config: UserConfig, configPath: string): void; -//# sourceMappingURL=config-prompts.d.ts.map \ No newline at end of file diff --git a/dist/src/cli/utils/config-prompts.js b/dist/src/cli/utils/config-prompts.js deleted file mode 100644 index 3058e13..0000000 --- a/dist/src/cli/utils/config-prompts.js +++ /dev/null @@ -1,171 +0,0 @@ -import inquirer from 'inquirer'; -import chalk from 'chalk'; -import * as fs from 'fs'; -export function getExistingConfig(projectPath) { - const configPath = `${projectPath}/.pragent.config.json`; - if (fs.existsSync(configPath)) { - try { - return JSON.parse(fs.readFileSync(configPath, 'utf-8')); - } - catch { - return null; - } - } - return null; -} -export async function promptFullConfig(projectPath, options = {}) { - const existingConfig = getExistingConfig(projectPath); - const { provider } = await inquirer.prompt([ - { - type: 'list', - name: 'provider', - message: 'Select AI provider:', - choices: [ - { name: 'Anthropic Claude (Recommended)', value: 'claude' }, - { name: 'OpenAI GPT', value: 'openai' }, - { name: 'Google Gemini', value: 'google' }, - ], - default: existingConfig?.ai?.provider || 'claude', - }, - ]); - let modelChoices = []; - let defaultModel = ''; - if (provider === 'claude') { - modelChoices = [ - { name: 'Claude Sonnet 4.5 (Recommended)', value: 'claude-sonnet-4-5-20250929' }, - { name: 'Claude Sonnet 3.5', value: 'claude-3-5-sonnet-20241022' }, - { name: 'Claude Opus', value: 'claude-3-opus-20240229' }, - ]; - defaultModel = 'claude-sonnet-4-5-20250929'; - } - else if (provider === 'openai') { - modelChoices = [ - { name: 'GPT-4 Turbo', value: 'gpt-4-turbo-preview' }, - { name: 'GPT-4', value: 'gpt-4' }, - { name: 'GPT-3.5 Turbo', value: 'gpt-3.5-turbo' }, - ]; - defaultModel = 'gpt-4-turbo-preview'; - } - else if (provider === 'google') { - modelChoices = [ - { name: 'Gemini Pro', value: 'gemini-pro' }, - { name: 'Gemini Ultra', value: 'gemini-ultra' }, - ]; - defaultModel = 'gemini-pro'; - } - const { selectedModel } = await inquirer.prompt([ - { - type: 'list', - name: 'selectedModel', - message: 'Select model:', - choices: modelChoices, - default: existingConfig?.ai?.model || defaultModel, - }, - ]); - const answers = { - provider, - selectedModel, - }; - if (options.includeApiKey !== false) { - const apiKeyPrompts = await inquirer.prompt([ - { - type: 'password', - name: 'apiKey', - message: `Enter ${provider.toUpperCase()} API key (or leave empty to use environment variable):`, - mask: '*', - }, - { - type: 'confirm', - name: 'saveApiKey', - message: 'Save API key to config file? (will be added to .gitignore)', - default: false, - when: (promptAnswers) => !!promptAnswers.apiKey, - }, - ]); - answers.apiKey = apiKeyPrompts.apiKey; - answers.saveApiKey = apiKeyPrompts.saveApiKey; - } - if (options.includeAnalysisPreferences !== false) { - const analysisPrompts = await inquirer.prompt([ - { - type: 'list', - name: 'defaultMode', - message: 'Default analysis mode:', - choices: [ - { name: 'Full (summary + risks + complexity)', value: 'full' }, - { name: 'Summary only', value: 'summary' }, - { name: 'Risks only', value: 'risks' }, - { name: 'Complexity only', value: 'complexity' }, - ], - default: existingConfig?.analysis?.defaultMode || 'full', - }, - { - type: 'confirm', - name: 'autoDetectAgent', - message: 'Auto-detect when to use intelligent agent for large diffs?', - default: existingConfig?.analysis?.autoDetectAgent !== false, - }, - ]); - answers.defaultMode = analysisPrompts.defaultMode; - answers.autoDetectAgent = analysisPrompts.autoDetectAgent; - } - return { answers, existingConfig }; -} -export async function promptProvider(defaultProvider) { - const { provider } = await inquirer.prompt([ - { - type: 'list', - name: 'provider', - message: 'Select AI provider:', - choices: [ - { name: 'Anthropic Claude', value: 'claude' }, - { name: 'OpenAI GPT', value: 'openai' }, - { name: 'Google Gemini', value: 'google' }, - ], - default: defaultProvider || 'claude', - }, - ]); - return provider; -} -export async function promptApiKey(provider) { - const { apiKey } = await inquirer.prompt([ - { - type: 'password', - name: 'apiKey', - message: `Enter ${provider.toUpperCase()} API key:`, - mask: '*', - validate: (input) => { - if (!input || input.trim().length === 0) { - return 'API key is required'; - } - return true; - }, - }, - ]); - return apiKey; -} -export async function promptConfirm(message, defaultValue = true) { - const { confirmed } = await inquirer.prompt([ - { - type: 'confirm', - name: 'confirmed', - message, - default: defaultValue, - }, - ]); - return confirmed; -} -export function displayConfigSummary(config, configPath) { - console.log(chalk.green('\n✅ Configuration saved successfully!')); - console.log(chalk.cyan('\n📝 Configuration Summary:')); - console.log(` • Config file: ${configPath}`); - console.log(` • AI Provider: ${config.ai?.provider}`); - console.log(` • Model: ${config.ai?.model}`); - console.log(` • Default Mode: ${config.analysis?.defaultMode || 'full'}`); - console.log(` • Auto Agent: ${config.analysis?.autoDetectAgent ? 'Enabled' : 'Disabled'}`); - console.log(chalk.cyan('\n💡 Next Steps:')); - console.log(' 1. Run: pr-agent analyze'); - console.log(' 2. Or: pr-agent analyze --staged'); - console.log(' 3. Or: pr-agent help'); -} -//# sourceMappingURL=config-prompts.js.map \ No newline at end of file diff --git a/dist/src/cli/utils/config-prompts.js.map b/dist/src/cli/utils/config-prompts.js.map deleted file mode 100644 index a0cdd1e..0000000 --- a/dist/src/cli/utils/config-prompts.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"config-prompts.js","sourceRoot":"","sources":["../../../../src/cli/utils/config-prompts.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/index.d.ts b/dist/src/index.d.ts deleted file mode 100644 index 6fd875b..0000000 --- a/dist/src/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Probot } from 'probot'; -declare const _default: (app: Probot) => void; -export default _default; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/src/index.js b/dist/src/index.js deleted file mode 100644 index d0cf7f5..0000000 --- a/dist/src/index.js +++ /dev/null @@ -1,86 +0,0 @@ -import { PRAnalyzerAgent } from './agents/pr-analyzer-agent.js'; -const apiKey = process.env.ANTHROPIC_API_KEY; -function formatAnalysisForGitHub(result) { - let output = ''; - if (result.summary) { - output += `### 📋 Summary\n${result.summary}\n\n`; - } - if (result.overallRisks && result.overallRisks.length > 0) { - output += `### ⚠️ Risks Identified\n`; - result.overallRisks.forEach((risk, i) => { - output += `${i + 1}. ${risk}\n`; - }); - output += '\n'; - } - if (result.overallComplexity) { - output += `### 📊 Complexity Score: ${result.overallComplexity}/5\n\n`; - } - if (result.recommendations && result.recommendations.length > 0) { - output += `### 💡 Recommendations\n`; - result.recommendations.forEach((rec, i) => { - output += `${i + 1}. ${rec}\n`; - }); - output += '\n'; - } - if (result.fileAnalyses && result.fileAnalyses.size > 0) { - const files = Array.from(result.fileAnalyses.entries()); - const sortedFiles = files - .sort((a, b) => b[1].complexity - a[1].complexity) - .slice(0, 5); - if (sortedFiles.length > 0) { - output += `### 📁 Files of Interest\n`; - sortedFiles.forEach(([path, analysis]) => { - output += `- **${path}** (complexity: ${analysis.complexity}/5)\n`; - if (analysis.risks && analysis.risks.length > 0) { - output += ` - ⚠️ ${analysis.risks.join(', ')}\n`; - } - }); - } - } - return output; -} -export default (app) => { - app.log.info('🤖 PR Agent (LangChain) started'); - app.on(['pull_request.opened', 'pull_request.synchronize'], async (context) => { - const { pull_request: pr, repository } = context.payload; - app.log.info(`Analyzing PR #${pr.number} in ${repository.full_name}`); - try { - app.log.info('Getting PR diffs'); - const diff = await getPRDiffs(context); - if (!apiKey) { - throw new Error('Anthropic API key is not set'); - } - app.log.info('Running LangChain agent analysis...'); - const agent = new PRAnalyzerAgent(apiKey); - const result = await agent.analyze(diff, pr.title); - const summary = formatAnalysisForGitHub(result); - await context.octokit.issues.createComment({ - owner: repository.owner.login, - repo: repository.name, - issue_number: pr.number, - body: `## 🤖 AI Analysis (LangChain Agent)\n\n${summary}` - }); - app.log.info(`Analysis posted for PR #${pr.number}`); - } - catch (error) { - app.log.error('Error analyzing PR:', error); - } - }); -}; -async function getPRDiffs(context) { - try { - const { pull_request: pr, repository } = context.payload; - const { data: files } = await context.octokit.pulls.listFiles({ - owner: repository.owner.login, - repo: repository.name, - pull_number: pr.number - }); - const diff = files.map((f) => `--- ${f.filename}\n${f.patch}`).join('\n'); - return diff; - } - catch (error) { - console.error('Error fetching PR diff:', error); - throw new Error('Failed to fetch PR diff'); - } -} -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/src/index.js.map b/dist/src/index.js.map deleted file mode 100644 index 8f34a4d..0000000 --- a/dist/src/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/pr-agent.d.ts b/dist/src/pr-agent.d.ts deleted file mode 100644 index 46126c0..0000000 --- a/dist/src/pr-agent.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { PRAnalyzerAgent } from './agents/pr-analyzer-agent.js'; -export type { DiffFile, AnalysisMode, AgentAnalysisResult, FileAnalysis, AgentContext, AgentResult, AgentMetadata, } from './types/agent.types.js'; -export { PRAnalyzerAgent as PRAgent } from './agents/pr-analyzer-agent.js'; -export { PRAnalyzerAgent as PRAnalysisAgent } from './agents/pr-analyzer-agent.js'; -//# sourceMappingURL=pr-agent.d.ts.map \ No newline at end of file diff --git a/dist/src/pr-agent.js b/dist/src/pr-agent.js deleted file mode 100644 index 64f9198..0000000 --- a/dist/src/pr-agent.js +++ /dev/null @@ -1,4 +0,0 @@ -export { PRAnalyzerAgent } from './agents/pr-analyzer-agent.js'; -export { PRAnalyzerAgent as PRAgent } from './agents/pr-analyzer-agent.js'; -export { PRAnalyzerAgent as PRAnalysisAgent } from './agents/pr-analyzer-agent.js'; -//# sourceMappingURL=pr-agent.js.map \ No newline at end of file diff --git a/dist/src/pr-agent.js.map b/dist/src/pr-agent.js.map deleted file mode 100644 index 47f0c36..0000000 --- a/dist/src/pr-agent.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"pr-agent.js","sourceRoot":"","sources":["../../src/pr-agent.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAchE,OAAO,EAAE,eAAe,IAAI,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,MAAM,+BAA+B,CAAC"} \ No newline at end of file diff --git a/dist/src/tools/index.d.ts b/dist/src/tools/index.d.ts deleted file mode 100644 index 5873897..0000000 --- a/dist/src/tools/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { parseDiff, createFileAnalyzerTool, createRiskDetectorTool, createComplexityScorerTool, createSummaryGeneratorTool, createCodeSuggestionTool, } from './pr-analysis-tools.js'; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/src/tools/index.js b/dist/src/tools/index.js deleted file mode 100644 index d8604db..0000000 --- a/dist/src/tools/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { parseDiff, createFileAnalyzerTool, createRiskDetectorTool, createComplexityScorerTool, createSummaryGeneratorTool, createCodeSuggestionTool, } from './pr-analysis-tools.js'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/src/tools/index.js.map b/dist/src/tools/index.js.map deleted file mode 100644 index 7575999..0000000 --- a/dist/src/tools/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,wBAAwB,CAAC"} \ No newline at end of file diff --git a/dist/src/tools/pr-analysis-tools.d.ts b/dist/src/tools/pr-analysis-tools.d.ts deleted file mode 100644 index ff111fe..0000000 --- a/dist/src/tools/pr-analysis-tools.d.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { DynamicStructuredTool } from '@langchain/core/tools'; -import { z } from 'zod'; -import { DiffFile } from '../types/agent.types.js'; -export declare function parseDiff(diff: string): DiffFile[]; -export declare function createFileAnalyzerTool(): DynamicStructuredTool, { - filePath: string; - diffContent: string; -}, { - filePath: string; - diffContent: string; -}, string>; -export declare function createRiskDetectorTool(): DynamicStructuredTool; -}, "strip", z.ZodTypeAny, { - diff: string; - context?: string | undefined; -}, { - diff: string; - context?: string | undefined; -}>, { - diff: string; - context?: string | undefined; -}, { - diff: string; - context?: string | undefined; -}, string>; -export declare function createComplexityScorerTool(): DynamicStructuredTool; - totalChanges: z.ZodNumber; -}, "strip", z.ZodTypeAny, { - filesAnalyzed: any[]; - totalChanges: number; -}, { - filesAnalyzed: any[]; - totalChanges: number; -}>, { - filesAnalyzed: any[]; - totalChanges: number; -}, { - filesAnalyzed: any[]; - totalChanges: number; -}, string>; -export declare function createSummaryGeneratorTool(): DynamicStructuredTool; - title: z.ZodOptional; -}, "strip", z.ZodTypeAny, { - files: any[]; - title?: string | undefined; -}, { - files: any[]; - title?: string | undefined; -}>, { - files: any[]; - title?: string | undefined; -}, { - files: any[]; - title?: string | undefined; -}, string>; -export declare function createCodeSuggestionTool(): DynamicStructuredTool; - prContext: z.ZodOptional; -}, "strip", z.ZodTypeAny, { - filePath: string; - reviewerComment: string; - codeSnippet: string; - prTitle?: string | undefined; - prContext?: string | undefined; -}, { - filePath: string; - reviewerComment: string; - codeSnippet: string; - prTitle?: string | undefined; - prContext?: string | undefined; -}>, { - filePath: string; - reviewerComment: string; - codeSnippet: string; - prTitle?: string | undefined; - prContext?: string | undefined; -}, { - filePath: string; - reviewerComment: string; - codeSnippet: string; - prTitle?: string | undefined; - prContext?: string | undefined; -}, string>; -//# sourceMappingURL=pr-analysis-tools.d.ts.map \ No newline at end of file diff --git a/dist/src/tools/pr-analysis-tools.js b/dist/src/tools/pr-analysis-tools.js deleted file mode 100644 index b8ebde0..0000000 --- a/dist/src/tools/pr-analysis-tools.js +++ /dev/null @@ -1,315 +0,0 @@ -import { DynamicStructuredTool } from '@langchain/core/tools'; -import { z } from 'zod'; -export function parseDiff(diff) { - const files = []; - const lines = diff.split('\n'); - let currentFile = null; - let currentDiff = []; - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (line.startsWith('diff --git')) { - if (currentFile) { - files.push({ - ...currentFile, - diff: currentDiff.join('\n'), - }); - } - const match = line.match(/^diff --git a\/(.+?) b\/(.+?)$/); - if (match) { - const filePath = match[2] !== '/dev/null' ? match[2] : match[1]; - currentFile = { - path: filePath, - additions: 0, - deletions: 0, - language: detectLanguage(filePath), - }; - currentDiff = [line]; - } - } - else if (line.startsWith('new file') && currentFile) { - currentFile.status = 'A'; - currentDiff.push(line); - } - else if (line.startsWith('deleted file') && currentFile) { - currentFile.status = 'D'; - currentDiff.push(line); - } - else if (line.startsWith('rename from') && currentFile) { - currentFile.status = 'R'; - const oldPath = line.replace('rename from ', '').trim(); - currentFile.oldPath = oldPath; - currentDiff.push(line); - } - else if (line.startsWith('+') && !line.startsWith('+++') && currentFile) { - currentFile.additions = (currentFile.additions || 0) + 1; - currentDiff.push(line); - } - else if (line.startsWith('-') && !line.startsWith('---') && currentFile) { - currentFile.deletions = (currentFile.deletions || 0) + 1; - currentDiff.push(line); - } - else if (currentFile) { - currentDiff.push(line); - } - } - if (currentFile) { - files.push({ - ...currentFile, - diff: currentDiff.join('\n'), - }); - } - return files; -} -function detectLanguage(filePath) { - const ext = filePath.split('.').pop()?.toLowerCase(); - const languageMap = { - ts: 'typescript', - tsx: 'typescript', - js: 'javascript', - jsx: 'javascript', - py: 'python', - java: 'java', - go: 'go', - rs: 'rust', - rb: 'ruby', - php: 'php', - cs: 'csharp', - cpp: 'cpp', - c: 'c', - swift: 'swift', - kt: 'kotlin', - yaml: 'yaml', - yml: 'yaml', - json: 'json', - md: 'markdown', - }; - return languageMap[ext || ''] || 'unknown'; -} -export function createFileAnalyzerTool() { - return new DynamicStructuredTool({ - name: 'analyze_file', - description: 'Analyze a specific file from the diff to identify risks, complexity, and provide recommendations', - schema: z.object({ - filePath: z.string().describe('Path of the file to analyze'), - diffContent: z.string().describe('The diff content for this file'), - }), - func: async ({ filePath, diffContent }) => { - const additions = (diffContent.match(/^\+[^+]/gm) || []).length; - const deletions = (diffContent.match(/^-[^-]/gm) || []).length; - const totalChanges = additions + deletions; - let complexity = 1; - if (totalChanges > 100) - complexity = 4; - else if (totalChanges > 50) - complexity = 3; - else if (totalChanges > 20) - complexity = 2; - const risks = []; - if (/eval\(|exec\(|system\(/i.test(diffContent)) { - risks.push('Potentially dangerous function calls detected (eval, exec, system)'); - } - if (/password|secret|api[_-]?key|token/i.test(diffContent) && /['"]/i.test(diffContent)) { - risks.push('Possible hardcoded credentials or secrets'); - } - if (/TODO|FIXME|XXX|HACK/i.test(diffContent)) { - risks.push('Contains TODO/FIXME comments indicating incomplete work'); - } - if (totalChanges > 200) { - risks.push('Very large change set - difficult to review thoroughly'); - } - const hasTryCatch = /try\s*{|catch\s*\(/i.test(diffContent); - const hasThrow = /throw\s+/i.test(diffContent); - if (hasThrow && !hasTryCatch) { - risks.push('Throws errors without apparent error handling'); - } - return JSON.stringify({ - path: filePath, - additions, - deletions, - complexity, - risks, - language: detectLanguage(filePath), - }); - }, - }); -} -export function createRiskDetectorTool() { - return new DynamicStructuredTool({ - name: 'detect_risks', - description: 'Detect security, quality, and breaking change risks in the PR', - schema: z.object({ - diff: z.string().describe('The full diff to analyze for risks'), - context: z.string().optional().describe('Additional context about the changes'), - }), - func: async ({ diff, context }) => { - const risks = []; - if (/sql.*=.*\+|SQL.*=.*\+/i.test(diff)) { - risks.push({ - type: 'security', - severity: 'high', - description: 'Potential SQL injection - string concatenation in SQL queries', - }); - } - if (/innerHTML|dangerouslySetInnerHTML/i.test(diff)) { - risks.push({ - type: 'security', - severity: 'medium', - description: 'XSS risk - using innerHTML or dangerouslySetInnerHTML', - }); - } - if (/export\s+(interface|type|class|function)\s+\w+/i.test(diff) && /-.*export/i.test(diff)) { - risks.push({ - type: 'breaking', - severity: 'high', - description: 'Potential breaking change - modified or removed export', - }); - } - if ((diff.match(/console\.log/g) || []).length > 3) { - risks.push({ - type: 'quality', - severity: 'low', - description: 'Multiple console.log statements - consider using proper logging', - }); - } - if (/for.*for|while.*while/i.test(diff) && /O\(n\^2\)/i.test(diff)) { - risks.push({ - type: 'performance', - severity: 'medium', - description: 'Nested loops detected - potential O(n²) complexity', - }); - } - return JSON.stringify({ - riskCount: risks.length, - risks, - context: context || 'No additional context provided', - }); - }, - }); -} -export function createComplexityScorerTool() { - return new DynamicStructuredTool({ - name: 'score_complexity', - description: 'Calculate overall complexity score for the PR (1-5 scale)', - schema: z.object({ - filesAnalyzed: z.array(z.any()).describe('Array of analyzed files'), - totalChanges: z.number().describe('Total lines changed'), - }), - func: async ({ filesAnalyzed, totalChanges }) => { - let score = 1; - if (totalChanges > 500) - score = Math.max(score, 5); - else if (totalChanges > 300) - score = Math.max(score, 4); - else if (totalChanges > 150) - score = Math.max(score, 3); - else if (totalChanges > 50) - score = Math.max(score, 2); - const fileCount = filesAnalyzed.length; - if (fileCount > 20) - score = Math.max(score, 5); - else if (fileCount > 10) - score = Math.max(score, 4); - else if (fileCount > 5) - score = Math.max(score, 3); - const avgFileComplexity = filesAnalyzed.reduce((sum, f) => sum + (f.complexity || 1), 0) / Math.max(fileCount, 1); - if (avgFileComplexity >= 4) - score = Math.max(score, 5); - else if (avgFileComplexity >= 3) - score = Math.max(score, 4); - return JSON.stringify({ - overallComplexity: Math.min(score, 5), - factors: { - totalChanges, - fileCount, - avgFileComplexity: avgFileComplexity.toFixed(1), - }, - recommendation: score >= 4 - ? 'High complexity - consider breaking into smaller PRs' - : score >= 3 - ? 'Moderate complexity - ensure thorough testing' - : 'Low complexity - straightforward changes', - }); - }, - }); -} -export function createSummaryGeneratorTool() { - return new DynamicStructuredTool({ - name: 'generate_summary', - description: 'Generate a concise summary of PR changes', - schema: z.object({ - files: z.array(z.any()).describe('Array of changed files'), - title: z.string().optional().describe('PR title'), - }), - func: async ({ files, title }) => { - const filesByType = {}; - let totalAdditions = 0; - let totalDeletions = 0; - files.forEach((file) => { - const lang = file.language || 'other'; - filesByType[lang] = (filesByType[lang] || 0) + 1; - totalAdditions += file.additions || 0; - totalDeletions += file.deletions || 0; - }); - const mainLanguage = Object.entries(filesByType).sort((a, b) => b[1] - a[1])[0]?.[0] || 'unknown'; - return JSON.stringify({ - title: title || 'Untitled PR', - fileCount: files.length, - totalAdditions, - totalDeletions, - netChange: totalAdditions - totalDeletions, - mainLanguage, - filesByType, - summary: `Changes ${files.length} file(s) with ${totalAdditions} additions and ${totalDeletions} deletions. Primary language: ${mainLanguage}.`, - }); - }, - }); -} -export function createCodeSuggestionTool() { - return new DynamicStructuredTool({ - name: 'suggest_code_fix', - description: 'Generate a code fix suggestion based on a reviewer comment and the associated code snippet', - schema: z.object({ - reviewerComment: z.string().describe('The reviewer\'s comment describing the issue'), - codeSnippet: z.string().describe('The original code snippet to be fixed'), - filePath: z.string().describe('Path of the file containing the code'), - prTitle: z.string().optional().describe('PR title for context'), - prContext: z.string().optional().describe('Additional PR context (repo, branch, etc.)'), - }), - func: async ({ reviewerComment, codeSnippet, filePath, prTitle, prContext }) => { - const prompt = `You are an expert software engineer and code-fixer. You will take a reviewer comment and the associated code snippet and produce the corrected code snippet only. - -Context: -${prContext || '(no additional context)'} -- PR Title: ${prTitle || '(unknown)'} -- File: ${filePath} - -Reviewer comment: -${reviewerComment.trim()} - -Original code snippet: -\`\`\` -${codeSnippet} -\`\`\` - -Task: -1) Apply the reviewer's requested changes to the provided code snippet. -2) Output rules (MUST follow exactly): - - Return only the corrected code snippet (no explanations, no markdown fences, no extra text). - - If only a few lines changed you may return only the updated lines, but prefer returning the full corrected snippet when structural/context changes are required. - - Preserve original code style and indentation. - - If no changes are needed, reply with exactly: NO CHANGE - - Do not include filenames, metadata, or commentary. - -Produce the corrected code now.`; - return JSON.stringify({ - filePath, - originalCode: codeSnippet, - reviewerComment, - prompt, - status: 'ready', - message: 'Code suggestion prompt prepared. The agent will use this to generate the fix.', - }); - }, - }); -} -//# sourceMappingURL=pr-analysis-tools.js.map \ No newline at end of file diff --git a/dist/src/tools/pr-analysis-tools.js.map b/dist/src/tools/pr-analysis-tools.js.map deleted file mode 100644 index 32780e0..0000000 --- a/dist/src/tools/pr-analysis-tools.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"pr-analysis-tools.js","sourceRoot":"","sources":["../../../src/tools/pr-analysis-tools.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/src/types.d.ts b/dist/src/types.d.ts deleted file mode 100644 index bb141de..0000000 --- a/dist/src/types.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -export type AIProviderType = 'anthropic' | 'openai' | 'google'; -export interface PRInfo { - number: number; - title: string; - diff: string; - author: string; - repository: string; -} -export interface AnalysisResult { - summary: string; - risks: string[]; - complexity: number; -} -export interface ExtendedAnalysisResult extends AnalysisResult { - provider: AIProviderType; - model: string; - tokensUsed?: number; - recommendations?: string[]; -} -export interface PRAnalyzerConfig { - analysis: { - maxComplexity: number; - includeRisks: boolean; - includeComplexity: boolean; - }; - ai: { - provider: AIProviderType; - fallbackProviders?: AIProviderType[]; - providers: { - [K in AIProviderType]?: { - model: string; - maxTokens: number; - temperature: number; - baseUrl?: string; - timeout?: number; - }; - }; - }; - files: { - include: string[]; - exclude: string[]; - }; -} -//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/dist/src/types.js b/dist/src/types.js deleted file mode 100644 index 718fd38..0000000 --- a/dist/src/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dist/src/types/agent.types.d.ts b/dist/src/types/agent.types.d.ts deleted file mode 100644 index 4a7a311..0000000 --- a/dist/src/types/agent.types.d.ts +++ /dev/null @@ -1,68 +0,0 @@ -export interface DiffFile { - path: string; - additions: number; - deletions: number; - diff: string; - language?: string; - status?: 'A' | 'M' | 'D' | 'R'; - oldPath?: string; -} -export interface AgentContext { - diff: string; - title?: string; - files: DiffFile[]; - repository?: string; - prNumber?: number; - tokenBudget: number; - maxCost: number; - mode: AnalysisMode; - config?: Record; -} -export interface AnalysisMode { - summary: boolean; - risks: boolean; - complexity: boolean; -} -export interface FileAnalysis { - path: string; - summary: string; - risks: string[]; - complexity: number; - changes: { - additions: number; - deletions: number; - }; - recommendations: string[]; -} -export interface AgentResult { - summary: string; - fileAnalyses: Map; - overallComplexity: number; - overallRisks: string[]; - recommendations: string[]; - insights: string[]; - reasoning: string[]; - provider: string; - model: string; - totalTokensUsed: number; - executionTime: number; - mode: AnalysisMode; -} -export type AgentAnalysisResult = AgentResult; -export interface AgentMetadata { - name: string; - version: string; - description: string; - capabilities: string[]; -} -export interface AgentExecutionOptions { - runnableConfig?: Record; - skipSelfRefinement?: boolean; - maxQuestionsPerIteration?: number; -} -export declare enum AgentPriority { - HIGH = "high", - MEDIUM = "medium", - LOW = "low" -} -//# sourceMappingURL=agent.types.d.ts.map \ No newline at end of file diff --git a/dist/src/types/agent.types.js b/dist/src/types/agent.types.js deleted file mode 100644 index c52030b..0000000 --- a/dist/src/types/agent.types.js +++ /dev/null @@ -1,7 +0,0 @@ -export var AgentPriority; -(function (AgentPriority) { - AgentPriority["HIGH"] = "high"; - AgentPriority["MEDIUM"] = "medium"; - AgentPriority["LOW"] = "low"; -})(AgentPriority || (AgentPriority = {})); -//# sourceMappingURL=agent.types.js.map \ No newline at end of file diff --git a/dist/src/types/agent.types.js.map b/dist/src/types/agent.types.js.map deleted file mode 100644 index 0dd6597..0000000 --- a/dist/src/types/agent.types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"agent.types.js","sourceRoot":"","sources":["../../../src/types/agent.types.ts"],"names":[],"mappings":"AA4EA,MAAM,CAAN,IAAY,aAIX;AAJD,WAAY,aAAa;IACvB,8BAAa,CAAA;IACb,kCAAiB,CAAA;IACjB,4BAAW,CAAA;AACb,CAAC,EAJW,aAAa,KAAb,aAAa,QAIxB"} \ No newline at end of file diff --git a/dist/tests/analyzer.test.d.ts b/dist/tests/analyzer.test.d.ts deleted file mode 100644 index 0900b66..0000000 --- a/dist/tests/analyzer.test.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=analyzer.test.d.ts.map \ No newline at end of file diff --git a/dist/tests/analyzer.test.js b/dist/tests/analyzer.test.js deleted file mode 100644 index 4e30547..0000000 --- a/dist/tests/analyzer.test.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const analyzer_1 = require("../src/analyzer"); -jest.mock('../src/providers/factory', () => ({ - createProvider: jest.fn(() => ({ - analyze: jest.fn().mockResolvedValue({ - summary: 'Test summary', - risks: ['Risk 1', 'Risk 2'], - complexity: 3, - provider: 'claude', - model: 'claude-3-5-sonnet-20241022', - tokensUsed: 100 - }) - })) -})); -describe('Analyzer', () => { - describe('analyzePR', () => { - it('should analyze PR with valid diff', async () => { - const result = await (0, analyzer_1.analyzePR)('test diff', 'Test PR'); - expect(result).toBeDefined(); - expect(result.summary).toBe('Test summary'); - expect(result.risks).toHaveLength(2); - expect(result.complexity).toBe(3); - expect(result.provider).toBe('claude'); - }); - it('should throw error for empty diff', async () => { - await expect((0, analyzer_1.analyzePR)('')).rejects.toThrow('Diff must be a non-empty string'); - }); - it('should throw error for null diff', async () => { - await expect((0, analyzer_1.analyzePR)(null)).rejects.toThrow('Diff must be a non-empty string'); - }); - it('should throw error for non-string diff', async () => { - await expect((0, analyzer_1.analyzePR)(123)).rejects.toThrow('Diff must be a non-empty string'); - }); - it('should use default config when none provided', async () => { - const result = await (0, analyzer_1.analyzePR)('test diff'); - expect(result).toBeDefined(); - }); - it('should accept repository and prNumber', async () => { - const result = await (0, analyzer_1.analyzePR)('test diff', 'Test PR', undefined, 'test/repo', 123); - expect(result).toBeDefined(); - }); - }); -}); -//# sourceMappingURL=analyzer.test.js.map \ No newline at end of file diff --git a/dist/tests/analyzer.test.js.map b/dist/tests/analyzer.test.js.map deleted file mode 100644 index 85c8ad9..0000000 --- a/dist/tests/analyzer.test.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"analyzer.test.js","sourceRoot":"","sources":["../../tests/analyzer.test.ts"],"names":[],"mappings":";;AACA,8CAA4C;AAI5C,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3C,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QAC7B,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YACnC,OAAO,EAAE,cAAc;YACvB,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;YAC3B,UAAU,EAAE,CAAC;YACb,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,4BAA4B;YACnC,UAAU,EAAE,GAAG;SAChB,CAAC;KACH,CAAC,CAAC;CACJ,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,MAAM,GAAG,MAAM,IAAA,oBAAS,EAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YAEvD,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;YAC7B,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,MAAM,CAAC,IAAA,oBAAS,EAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAChD,MAAM,MAAM,CAAC,IAAA,oBAAS,EAAC,IAAW,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;QAC1F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,MAAM,CAAC,IAAA,oBAAS,EAAC,GAAU,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;QACzF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,MAAM,GAAG,MAAM,IAAA,oBAAS,EAAC,WAAW,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,MAAM,GAAG,MAAM,IAAA,oBAAS,EAAC,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;YACpF,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/tests/providers/base.test.d.ts b/dist/tests/providers/base.test.d.ts deleted file mode 100644 index df2be78..0000000 --- a/dist/tests/providers/base.test.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=base.test.d.ts.map \ No newline at end of file diff --git a/dist/tests/providers/base.test.js b/dist/tests/providers/base.test.js deleted file mode 100644 index 6209207..0000000 --- a/dist/tests/providers/base.test.js +++ /dev/null @@ -1,172 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const base_1 = require("../../src/providers/base"); -class MockProvider extends base_1.BaseAIProvider { - getProviderType() { - return 'claude'; - } - async analyze(request) { - const parsed = this.parseResponse('**Summary**: Test summary\n\n**Potential Risks**:\n- Risk 1\n- Risk 2\n\n**Complexity**: 3/5'); - return { - ...parsed, - provider: 'claude', - model: this.config.model - }; - } - async validateConfig() { - return true; - } - getModelInfo() { - return { - name: 'Test Model', - maxTokens: 100000, - capabilities: this.getCapabilities() - }; - } - getCapabilities() { - return { - maxContextLength: 100000, - supportsImages: false, - supportsStreaming: false, - supportsFunctionCalling: false - }; - } - getApiKeyFromEnv() { - return process.env.TEST_API_KEY || ''; - } - testBuildPrompt(request) { - return this.buildPrompt(request); - } - testParseResponse(response) { - return this.parseResponse(response); - } - testIsDiffTooLarge(diff) { - return this.isDiffTooLarge(diff); - } - testTruncateDiff(diff) { - return this.truncateDiff(diff); - } -} -describe('BaseAIProvider', () => { - const validConfig = { - provider: 'claude', - model: 'test-model', - maxTokens: 1500, - temperature: 0.2, - apiKey: 'test-api-key-1234567890' - }; - describe('Constructor', () => { - it('should create provider with valid config', () => { - const provider = new MockProvider(validConfig); - expect(provider).toBeDefined(); - }); - it('should throw error for missing API key', () => { - const config = { ...validConfig, apiKey: undefined }; - expect(() => new MockProvider(config)).toThrow('API key is required'); - }); - it('should throw error for short API key', () => { - const config = { ...validConfig, apiKey: 'short' }; - expect(() => new MockProvider(config)).toThrow('Invalid API key format'); - }); - }); - describe('buildPrompt', () => { - it('should build prompt with all fields', () => { - const provider = new MockProvider(validConfig); - const request = { - diff: 'test diff', - title: 'Test PR', - repository: 'test/repo', - prNumber: 123 - }; - const prompt = provider.testBuildPrompt(request); - expect(prompt).toContain('test diff'); - expect(prompt).toContain('Test PR'); - expect(prompt).toContain('test/repo'); - expect(prompt).toContain('#123'); - }); - it('should throw error for empty diff', () => { - const provider = new MockProvider(validConfig); - const request = { diff: '' }; - expect(() => provider.testBuildPrompt(request)).toThrow('Diff is required and cannot be empty'); - }); - it('should throw error for very large diff', () => { - const provider = new MockProvider(validConfig); - const largeDiff = 'x'.repeat(2000000); - const request = { diff: largeDiff }; - expect(() => provider.testBuildPrompt(request)).toThrow('Diff is too large'); - }); - }); - describe('parseResponse', () => { - it('should parse valid response', () => { - const provider = new MockProvider(validConfig); - const response = ` -**Summary**: This PR adds new features - -**Potential Risks**: -- Risk 1 -- Risk 2 - -**Complexity**: 4/5 - `; - const parsed = provider.testParseResponse(response); - expect(parsed.summary).toContain('This PR adds new features'); - expect(parsed.risks).toHaveLength(2); - expect(parsed.complexity).toBe(4); - }); - it('should handle "None" risks', () => { - const provider = new MockProvider(validConfig); - const response = ` -**Summary**: Test - -**Potential Risks**: None - -**Complexity**: 2/5 - `; - const parsed = provider.testParseResponse(response); - expect(parsed.risks).toHaveLength(0); - }); - it('should default to complexity 3 if not found', () => { - const provider = new MockProvider(validConfig); - const response = '**Summary**: Test summary'; - const parsed = provider.testParseResponse(response); - expect(parsed.complexity).toBe(3); - }); - it('should clamp complexity to 1-5 range', () => { - const provider = new MockProvider(validConfig); - const response1 = '**Complexity**: 0/5'; - const response2 = '**Complexity**: 10/5'; - const parsed1 = provider.testParseResponse(response1); - const parsed2 = provider.testParseResponse(response2); - expect(parsed1.complexity).toBe(1); - expect(parsed2.complexity).toBe(5); - }); - }); - describe('isDiffTooLarge', () => { - it('should return false for small diff', () => { - const provider = new MockProvider(validConfig); - const smallDiff = 'x'.repeat(1000); - expect(provider.testIsDiffTooLarge(smallDiff)).toBe(false); - }); - it('should return true for very large diff', () => { - const provider = new MockProvider(validConfig); - const largeDiff = 'x'.repeat(400000); - expect(provider.testIsDiffTooLarge(largeDiff)).toBe(true); - }); - }); - describe('truncateDiff', () => { - it('should not truncate small diff', () => { - const provider = new MockProvider(validConfig); - const smallDiff = 'small diff'; - const truncated = provider.testTruncateDiff(smallDiff); - expect(truncated).toBe(smallDiff); - }); - it('should truncate large diff', () => { - const provider = new MockProvider(validConfig); - const largeDiff = 'x'.repeat(500000); - const truncated = provider.testTruncateDiff(largeDiff); - expect(truncated.length).toBeLessThan(largeDiff.length); - expect(truncated).toContain('[... diff truncated due to size limits ...]'); - }); - }); -}); -//# sourceMappingURL=base.test.js.map \ No newline at end of file diff --git a/dist/tests/providers/base.test.js.map b/dist/tests/providers/base.test.js.map deleted file mode 100644 index 25b9359..0000000 --- a/dist/tests/providers/base.test.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"base.test.js","sourceRoot":"","sources":["../../../tests/providers/base.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tests/providers/factory.test.d.ts b/dist/tests/providers/factory.test.d.ts deleted file mode 100644 index 523153e..0000000 --- a/dist/tests/providers/factory.test.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=factory.test.d.ts.map \ No newline at end of file diff --git a/dist/tests/providers/factory.test.js b/dist/tests/providers/factory.test.js deleted file mode 100644 index fb89613..0000000 --- a/dist/tests/providers/factory.test.js +++ /dev/null @@ -1,103 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const factory_1 = require("../../src/providers/factory"); -describe('Provider Factory', () => { - describe('createProvider', () => { - it('should create Claude provider with valid config', () => { - const config = { - provider: 'claude', - model: 'claude-3-5-sonnet-20241022', - maxTokens: 1500, - temperature: 0.2, - apiKey: 'test-api-key-1234567890' - }; - const provider = (0, factory_1.createProvider)(config); - expect(provider).toBeDefined(); - expect(provider.getProviderType()).toBe('claude'); - }); - it('should throw error for missing config', () => { - expect(() => (0, factory_1.createProvider)(null)).toThrow('Provider configuration is required'); - }); - it('should throw error for missing provider type', () => { - const config = { - model: 'test', - maxTokens: 1500, - temperature: 0.2 - }; - expect(() => (0, factory_1.createProvider)(config)).toThrow('Provider type is required'); - }); - it('should throw error for missing model', () => { - const config = { - provider: 'claude', - maxTokens: 1500, - temperature: 0.2 - }; - expect(() => (0, factory_1.createProvider)(config)).toThrow('Model is required'); - }); - it('should throw error for invalid maxTokens', () => { - const config = { - provider: 'claude', - model: 'test', - maxTokens: -1, - temperature: 0.2 - }; - expect(() => (0, factory_1.createProvider)(config)).toThrow('maxTokens must be a positive number'); - }); - it('should throw error for invalid temperature', () => { - const config = { - provider: 'claude', - model: 'test', - maxTokens: 1500, - temperature: 3, - apiKey: 'test-key-123' - }; - expect(() => (0, factory_1.createProvider)(config)).toThrow('temperature must be a number between 0 and 2'); - }); - it('should throw error for unregistered provider', () => { - const config = { - provider: 'openai', - model: 'gpt-4', - maxTokens: 1500, - temperature: 0.2, - apiKey: 'test-key' - }; - expect(() => (0, factory_1.createProvider)(config)).toThrow('not registered'); - }); - }); - describe('getAvailableProviders', () => { - it('should return array of available providers', () => { - const providers = (0, factory_1.getAvailableProviders)(); - expect(Array.isArray(providers)).toBe(true); - expect(providers).toContain('claude'); - }); - }); - describe('isProviderAvailable', () => { - it('should return true for Claude', () => { - expect((0, factory_1.isProviderAvailable)('claude')).toBe(true); - }); - it('should return false for unregistered providers', () => { - expect((0, factory_1.isProviderAvailable)('openai')).toBe(false); - expect((0, factory_1.isProviderAvailable)('gemini')).toBe(false); - }); - }); - describe('getDefaultConfig', () => { - it('should return default config for Claude', () => { - const config = (0, factory_1.getDefaultConfig)('claude'); - expect(config.provider).toBe('claude'); - expect(config.model).toBe('claude-3-5-sonnet-20241022'); - expect(config.maxTokens).toBe(1500); - expect(config.temperature).toBe(0.2); - }); - it('should return default config for OpenAI', () => { - const config = (0, factory_1.getDefaultConfig)('openai'); - expect(config.provider).toBe('openai'); - expect(config.model).toBe('gpt-4-turbo'); - }); - it('should return default config for Gemini', () => { - const config = (0, factory_1.getDefaultConfig)('gemini'); - expect(config.provider).toBe('gemini'); - expect(config.model).toBe('gemini-pro'); - }); - }); -}); -//# sourceMappingURL=factory.test.js.map \ No newline at end of file diff --git a/dist/tests/providers/factory.test.js.map b/dist/tests/providers/factory.test.js.map deleted file mode 100644 index b63a8c7..0000000 --- a/dist/tests/providers/factory.test.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"factory.test.js","sourceRoot":"","sources":["../../../tests/providers/factory.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tests/providers/types.test.d.ts b/dist/tests/providers/types.test.d.ts deleted file mode 100644 index 961011c..0000000 --- a/dist/tests/providers/types.test.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.test.d.ts.map \ No newline at end of file diff --git a/dist/tests/providers/types.test.js b/dist/tests/providers/types.test.js deleted file mode 100644 index cac565f..0000000 --- a/dist/tests/providers/types.test.js +++ /dev/null @@ -1,59 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const types_1 = require("../../src/providers/types"); -describe('Type Guards', () => { - describe('isValidProviderType', () => { - it('should validate correct provider types', () => { - expect((0, types_1.isValidProviderType)('claude')).toBe(true); - expect((0, types_1.isValidProviderType)('openai')).toBe(true); - expect((0, types_1.isValidProviderType)('gemini')).toBe(true); - }); - it('should reject invalid provider types', () => { - expect((0, types_1.isValidProviderType)('invalid')).toBe(false); - expect((0, types_1.isValidProviderType)('')).toBe(false); - expect((0, types_1.isValidProviderType)(null)).toBe(false); - expect((0, types_1.isValidProviderType)(undefined)).toBe(false); - expect((0, types_1.isValidProviderType)(123)).toBe(false); - }); - }); - describe('isAnalysisResponse', () => { - it('should validate correct analysis response', () => { - const validResponse = { - summary: 'Test summary', - risks: ['risk1', 'risk2'], - complexity: 3, - provider: 'claude', - model: 'claude-3-5-sonnet-20241022', - tokensUsed: 100 - }; - expect((0, types_1.isAnalysisResponse)(validResponse)).toBe(true); - }); - it('should reject invalid analysis responses', () => { - expect((0, types_1.isAnalysisResponse)(null)).toBe(false); - expect((0, types_1.isAnalysisResponse)(undefined)).toBe(false); - expect((0, types_1.isAnalysisResponse)({})).toBe(false); - expect((0, types_1.isAnalysisResponse)({ summary: 'test' })).toBe(false); - expect((0, types_1.isAnalysisResponse)({ - summary: 'test', - risks: 'not-array', - complexity: 1, - provider: 'claude', - model: 'test' - })).toBe(false); - }); - }); - describe('isProviderError', () => { - it('should validate correct provider errors', () => { - const error = new Error('test'); - error.provider = 'claude'; - error.retryable = true; - expect((0, types_1.isProviderError)(error)).toBe(true); - }); - it('should reject invalid provider errors', () => { - expect((0, types_1.isProviderError)(null)).toBe(false); - expect((0, types_1.isProviderError)(new Error('test'))).toBe(false); - expect((0, types_1.isProviderError)({ message: 'test' })).toBe(false); - }); - }); -}); -//# sourceMappingURL=types.test.js.map \ No newline at end of file diff --git a/dist/tests/providers/types.test.js.map b/dist/tests/providers/types.test.js.map deleted file mode 100644 index c89c7a9..0000000 --- a/dist/tests/providers/types.test.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.test.js","sourceRoot":"","sources":["../../../tests/providers/types.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/analyze-file-group.d.ts b/dist/tools/analyze-file-group.d.ts deleted file mode 100644 index 0d0d231..0000000 --- a/dist/tools/analyze-file-group.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Analyze file group tool - analyzes multiple files together - */ -import { DynamicStructuredTool } from '@langchain/core/tools'; -import type { ToolContext } from './types'; -export declare function createAnalyzeFileGroupTool(context: ToolContext): DynamicStructuredTool; diff --git a/dist/tools/analyze-file-group.js b/dist/tools/analyze-file-group.js deleted file mode 100644 index e54ed7d..0000000 --- a/dist/tools/analyze-file-group.js +++ /dev/null @@ -1,85 +0,0 @@ -"use strict"; -/** - * Analyze file group tool - analyzes multiple files together - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createAnalyzeFileGroupTool = createAnalyzeFileGroupTool; -const tools_1 = require("@langchain/core/tools"); -const zod_1 = require("zod"); -const prompts_1 = require("../prompts"); -const helpers_1 = require("./helpers"); -function createAnalyzeFileGroupTool(context) { - const { state, llm, provider, getFileContent, getDeletedFileContent } = context; - return new tools_1.DynamicStructuredTool({ - name: 'analyze_file_group', - description: 'Analyze a group of related files together. More efficient for related changes.', - schema: zod_1.z.object({ - filePaths: zod_1.z.array(zod_1.z.string()).describe('Array of file paths to analyze together'), - }), - func: async ({ filePaths }) => { - const alreadyAnalyzed = filePaths.filter(path => state.analyzedFiles.has(path)); - const files = state.pendingFiles.filter(f => filePaths.includes(f.path)); - if (files.length === 0) { - if (alreadyAnalyzed.length > 0) { - return JSON.stringify({ - message: `All ${filePaths.length} files already analyzed`, - alreadyAnalyzed: alreadyAnalyzed, - success: true - }); - } - return JSON.stringify({ - error: `No matching files found in pending list. Use get_current_state to see available files.`, - requestedFiles: filePaths, - suggestion: 'Call get_current_state to see which files need analysis' - }); - } - try { - const mode = state.mode || { summary: true, risks: true, complexity: true }; - const results = []; - for (const file of files) { - const { fileContent, analysisContext } = (0, helpers_1.prepareFileContent)(file, getFileContent, getDeletedFileContent); - const outputFormat = state.outputFormat || 'terminal'; - const isTerminal = outputFormat === 'terminal'; - const customPrompt = (0, prompts_1.buildFileAnalysisPrompt)(analysisContext, fileContent, `${file.path} (in group context)`, file.status || 'M', isTerminal, mode); - try { - const response = await llm.invoke(customPrompt); - const rawResponse = response.content; - const analysis = { - summary: rawResponse, - risks: [], - complexity: 3, - provider: provider.getProviderType(), - model: provider.config?.model || 'claude-sonnet-4-5-20250929', - tokensUsed: response.usage?.input_tokens ? - response.usage.input_tokens + (response.usage.output_tokens || 0) : - undefined - }; - (0, helpers_1.extractRisksAndComplexity)(rawResponse, analysis, state); - state.analyzedFiles.set(file.path, analysis); - results.push({ file: file.path, analysis }); - } - catch (error) { - results.push({ file: file.path, error: error.message }); - } - } - state.pendingFiles = state.pendingFiles.filter(f => !filePaths.includes(f.path)); - return JSON.stringify({ - success: true, - results, - filePaths, - analyzedCount: files.length, - remaining: state.pendingFiles.length, - message: `Successfully analyzed ${files.length} file(s). Remaining: ${state.pendingFiles.length} files` - }); - } - catch (error) { - return JSON.stringify({ - error: `Failed to analyze file group: ${error.message}`, - filePaths, - success: false - }); - } - }, - }); -} -//# sourceMappingURL=analyze-file-group.js.map \ No newline at end of file diff --git a/dist/tools/analyze-file-group.js.map b/dist/tools/analyze-file-group.js.map deleted file mode 100644 index d8306c1..0000000 --- a/dist/tools/analyze-file-group.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"analyze-file-group.js","sourceRoot":"","sources":["../../src/tools/analyze-file-group.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/check-imports.d.ts b/dist/tools/check-imports.d.ts deleted file mode 100644 index 375e509..0000000 --- a/dist/tools/check-imports.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Check imports tool - checks imports and usages - */ -import { DynamicStructuredTool } from '@langchain/core/tools'; -import type { ToolContext } from './types'; -export declare function createCheckImportsTool(context: ToolContext): DynamicStructuredTool | null; diff --git a/dist/tools/check-imports.js b/dist/tools/check-imports.js deleted file mode 100644 index 34a3e4b..0000000 --- a/dist/tools/check-imports.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; -/** - * Check imports tool - checks imports and usages - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createCheckImportsTool = createCheckImportsTool; -const tools_1 = require("@langchain/core/tools"); -const zod_1 = require("zod"); -const import_checker_1 = require("./import-checker"); -function createCheckImportsTool(context) { - const { state, githubApi, repository } = context; - if (!githubApi || !repository) { - return null; - } - return new tools_1.DynamicStructuredTool({ - name: 'check_imports_and_usages', - description: 'Check if imported modules/functions exist in the repository and verify their usage. Uses GitHub API.', - schema: zod_1.z.object({ - filePath: zod_1.z.string().describe('Path to the file to check imports for'), - }), - func: async ({ filePath }) => { - const file = state.pendingFiles.find(f => f.path === filePath) || - Array.from(state.analyzedFiles.keys()).find(k => k === filePath); - if (!file) { - const analyzedFile = state.analyzedFiles.get(filePath); - if (analyzedFile) { - return JSON.stringify({ message: 'File already analyzed, imports checked during analysis' }); - } - return JSON.stringify({ error: `File ${filePath} not found` }); - } - const fileObj = typeof file === 'string' ? state.pendingFiles.find(f => f.path === file) : file; - if (fileObj) { - const result = await (0, import_checker_1.checkImportsAndUsages)(fileObj, githubApi, repository); - return JSON.stringify(result); - } - return JSON.stringify({ error: 'File not found' }); - }, - }); -} -//# sourceMappingURL=check-imports.js.map \ No newline at end of file diff --git a/dist/tools/check-imports.js.map b/dist/tools/check-imports.js.map deleted file mode 100644 index 6ff350b..0000000 --- a/dist/tools/check-imports.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"check-imports.js","sourceRoot":"","sources":["../../src/tools/check-imports.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAOH,wDA+BC;AApCD,iDAA8D;AAC9D,6BAAwB;AACxB,qDAAyD;AAGzD,SAAgB,sBAAsB,CAAC,OAAoB;IACzD,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAEjD,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,6BAAqB,CAAC;QAC/B,IAAI,EAAE,0BAA0B;QAChC,WAAW,EAAE,sGAAsG;QACnH,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;SACvE,CAAC;QACF,IAAI,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAwB,EAAE,EAAE;YACjD,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;gBACjD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC;YAC9E,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,YAAY,GAAG,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACvD,IAAI,YAAY,EAAE,CAAC;oBACjB,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,wDAAwD,EAAE,CAAC,CAAC;gBAC/F,CAAC;gBACD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,QAAQ,QAAQ,YAAY,EAAE,CAAC,CAAC;YACjE,CAAC;YACD,MAAM,OAAO,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAChG,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,MAAM,GAAG,MAAM,IAAA,sCAAqB,EAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;YACD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACrD,CAAC;KACF,CAAC,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/dist/tools/coverage-analyzer.d.ts b/dist/tools/coverage-analyzer.d.ts new file mode 100644 index 0000000..fcabc4c --- /dev/null +++ b/dist/tools/coverage-analyzer.d.ts @@ -0,0 +1,115 @@ +/** + * Coverage Analyzer Tool for PR Analysis + * Integrates Istanbul/nyc coverage data and ESLint static analysis + * to provide coverage-based test suggestions + */ +export interface CoverageMetrics { + statements: { + covered: number; + total: number; + pct: number; + }; + branches: { + covered: number; + total: number; + pct: number; + }; + functions: { + covered: number; + total: number; + pct: number; + }; + lines: { + covered: number; + total: number; + pct: number; + }; +} +export interface FileCoverage { + path: string; + metrics: CoverageMetrics; + uncoveredLines: number[]; + uncoveredBranches: string[]; + uncoveredFunctions: string[]; +} +export interface UncoveredCode { + filePath: string; + functionName?: string; + lineRange: { + start: number; + end: number; + }; + type: 'function' | 'branch' | 'statement' | 'line'; + suggestion?: string; +} +export interface CoverageAnalysis { + overall: CoverageMetrics; + files: FileCoverage[]; + uncoveredCode: UncoveredCode[]; + timestamp: string; + hasReport: boolean; +} +export interface StaticAnalysisIssue { + filePath: string; + line: number; + column: number; + severity: 'error' | 'warning' | 'info'; + ruleId: string; + message: string; + suggestion?: string; +} +export interface StaticAnalysis { + issues: StaticAnalysisIssue[]; + summary: { + errors: number; + warnings: number; + info: number; + fixable: number; + }; + hasResults: boolean; +} +/** + * Detect if a coverage report exists and its format + */ +export declare function detectCoverageReport(repoPath?: string): { + found: boolean; + format: 'lcov' | 'json' | 'clover' | 'none'; + path: string | null; +}; +/** + * Parse coverage-summary.json (Istanbul/nyc format) + */ +export declare function parseCoverageJson(reportPath: string): CoverageAnalysis; +/** + * Parse lcov.info format coverage report + */ +export declare function parseLcovReport(reportPath: string): CoverageAnalysis; +/** + * Run ESLint on specified files or directory + */ +export declare function runEslintAnalysis(targetPath: string, options?: { + fix?: boolean; + format?: 'json' | 'stylish'; +}): Promise; +/** + * Get full coverage analysis from existing reports + */ +export declare function getCoverageAnalysis(repoPath?: string): CoverageAnalysis; +/** + * Run coverage analysis using nyc (generates report if needed) + */ +export declare function runCoverageAnalysis(repoPath?: string, options?: { + regenerate?: boolean; +}): Promise; +/** + * Get files with low coverage that need test suggestions + */ +export declare function getLowCoverageFiles(analysis: CoverageAnalysis, threshold?: number): FileCoverage[]; +/** + * Format coverage analysis for CLI output + */ +export declare function formatCoverageReport(analysis: CoverageAnalysis): string; +/** + * Format static analysis for CLI output + */ +export declare function formatStaticAnalysis(analysis: StaticAnalysis): string; diff --git a/dist/tools/coverage-analyzer.js b/dist/tools/coverage-analyzer.js new file mode 100644 index 0000000..62b4647 --- /dev/null +++ b/dist/tools/coverage-analyzer.js @@ -0,0 +1,493 @@ +/** + * Coverage Analyzer Tool for PR Analysis + * Integrates Istanbul/nyc coverage data and ESLint static analysis + * to provide coverage-based test suggestions + */ +import { exec } from 'child_process'; +import { promisify } from 'util'; +import fs from 'fs'; +import path from 'path'; +const execAsync = promisify(exec); +// ========== Coverage Report Detection ========== +/** + * Detect if a coverage report exists and its format + */ +export function detectCoverageReport(repoPath = '.') { + const coverageDir = path.join(repoPath, 'coverage'); + // Check for common coverage report locations + const lcovPath = path.join(coverageDir, 'lcov.info'); + const jsonPath = path.join(coverageDir, 'coverage-final.json'); + const jsonSummaryPath = path.join(coverageDir, 'coverage-summary.json'); + const cloverPath = path.join(coverageDir, 'clover.xml'); + if (fs.existsSync(jsonSummaryPath)) { + return { found: true, format: 'json', path: jsonSummaryPath }; + } + if (fs.existsSync(jsonPath)) { + return { found: true, format: 'json', path: jsonPath }; + } + if (fs.existsSync(lcovPath)) { + return { found: true, format: 'lcov', path: lcovPath }; + } + if (fs.existsSync(cloverPath)) { + return { found: true, format: 'clover', path: cloverPath }; + } + return { found: false, format: 'none', path: null }; +} +/** + * Parse coverage-summary.json (Istanbul/nyc format) + */ +export function parseCoverageJson(reportPath) { + try { + const content = fs.readFileSync(reportPath, 'utf-8'); + const data = JSON.parse(content); + const files = []; + const uncoveredCode = []; + // Extract overall metrics + const overall = data.total ? { + statements: { + covered: data.total.statements?.covered || 0, + total: data.total.statements?.total || 0, + pct: data.total.statements?.pct || 0, + }, + branches: { + covered: data.total.branches?.covered || 0, + total: data.total.branches?.total || 0, + pct: data.total.branches?.pct || 0, + }, + functions: { + covered: data.total.functions?.covered || 0, + total: data.total.functions?.total || 0, + pct: data.total.functions?.pct || 0, + }, + lines: { + covered: data.total.lines?.covered || 0, + total: data.total.lines?.total || 0, + pct: data.total.lines?.pct || 0, + }, + } : createEmptyMetrics(); + // Process each file + for (const [filePath, fileData] of Object.entries(data)) { + if (filePath === 'total') + continue; + const fd = fileData; + const metrics = { + statements: { + covered: fd.statements?.covered || 0, + total: fd.statements?.total || 0, + pct: fd.statements?.pct || 0, + }, + branches: { + covered: fd.branches?.covered || 0, + total: fd.branches?.total || 0, + pct: fd.branches?.pct || 0, + }, + functions: { + covered: fd.functions?.covered || 0, + total: fd.functions?.total || 0, + pct: fd.functions?.pct || 0, + }, + lines: { + covered: fd.lines?.covered || 0, + total: fd.lines?.total || 0, + pct: fd.lines?.pct || 0, + }, + }; + // Identify uncovered items + const uncoveredLines = []; + const uncoveredBranches = []; + const uncoveredFunctions = []; + // For low coverage files, add to uncovered code suggestions + if (metrics.lines.pct < 50) { + uncoveredCode.push({ + filePath, + type: 'line', + lineRange: { start: 1, end: metrics.lines.total }, + suggestion: `File has ${metrics.lines.pct.toFixed(1)}% line coverage. Consider adding tests.`, + }); + } + if (metrics.functions.pct < 50) { + uncoveredCode.push({ + filePath, + type: 'function', + lineRange: { start: 1, end: 1 }, + suggestion: `Only ${metrics.functions.covered}/${metrics.functions.total} functions are tested.`, + }); + } + files.push({ + path: filePath, + metrics, + uncoveredLines, + uncoveredBranches, + uncoveredFunctions, + }); + } + return { + overall, + files, + uncoveredCode, + timestamp: new Date().toISOString(), + hasReport: true, + }; + } + catch (error) { + console.error('Error parsing coverage report:', error); + return createEmptyAnalysis(); + } +} +/** + * Parse lcov.info format coverage report + */ +export function parseLcovReport(reportPath) { + try { + const content = fs.readFileSync(reportPath, 'utf-8'); + const lines = content.split('\n'); + const files = []; + const uncoveredCode = []; + let currentFile = null; + let currentMetrics = createEmptyMetrics(); + let currentUncoveredLines = []; + let currentUncoveredFunctions = []; + let totalLines = { covered: 0, total: 0 }; + let totalFunctions = { covered: 0, total: 0 }; + let totalBranches = { covered: 0, total: 0 }; + for (const line of lines) { + if (line.startsWith('SF:')) { + // Source file + currentFile = line.substring(3); + currentMetrics = createEmptyMetrics(); + currentUncoveredLines = []; + currentUncoveredFunctions = []; + } + else if (line.startsWith('DA:')) { + // Line coverage: DA:line_number,hit_count + const [lineNum, hitCount] = line.substring(3).split(',').map(Number); + currentMetrics.lines.total++; + if (hitCount > 0) { + currentMetrics.lines.covered++; + } + else { + currentUncoveredLines.push(lineNum); + } + } + else if (line.startsWith('FN:')) { + // Function: FN:line_number,function_name + currentMetrics.functions.total++; + } + else if (line.startsWith('FNDA:')) { + // Function hit data: FNDA:hit_count,function_name + const parts = line.substring(5).split(','); + const hitCount = parseInt(parts[0], 10); + const funcName = parts.slice(1).join(','); + if (hitCount > 0) { + currentMetrics.functions.covered++; + } + else { + currentUncoveredFunctions.push(funcName); + } + } + else if (line.startsWith('BRDA:')) { + // Branch: BRDA:line,block,branch,taken + const parts = line.substring(5).split(','); + currentMetrics.branches.total++; + if (parts[3] !== '-' && parseInt(parts[3], 10) > 0) { + currentMetrics.branches.covered++; + } + } + else if (line === 'end_of_record' && currentFile) { + // Calculate percentages + currentMetrics.lines.pct = currentMetrics.lines.total > 0 + ? (currentMetrics.lines.covered / currentMetrics.lines.total) * 100 + : 100; + currentMetrics.functions.pct = currentMetrics.functions.total > 0 + ? (currentMetrics.functions.covered / currentMetrics.functions.total) * 100 + : 100; + currentMetrics.branches.pct = currentMetrics.branches.total > 0 + ? (currentMetrics.branches.covered / currentMetrics.branches.total) * 100 + : 100; + currentMetrics.statements = currentMetrics.lines; // Approximate + // Accumulate totals + totalLines.covered += currentMetrics.lines.covered; + totalLines.total += currentMetrics.lines.total; + totalFunctions.covered += currentMetrics.functions.covered; + totalFunctions.total += currentMetrics.functions.total; + totalBranches.covered += currentMetrics.branches.covered; + totalBranches.total += currentMetrics.branches.total; + // Add low coverage files to uncovered code + if (currentMetrics.lines.pct < 50 && currentUncoveredLines.length > 0) { + uncoveredCode.push({ + filePath: currentFile, + type: 'line', + lineRange: { + start: Math.min(...currentUncoveredLines), + end: Math.max(...currentUncoveredLines) + }, + suggestion: `${currentUncoveredLines.length} lines without test coverage`, + }); + } + for (const funcName of currentUncoveredFunctions) { + uncoveredCode.push({ + filePath: currentFile, + functionName: funcName, + type: 'function', + lineRange: { start: 1, end: 1 }, + suggestion: `Function '${funcName}' has no test coverage`, + }); + } + files.push({ + path: currentFile, + metrics: { ...currentMetrics }, + uncoveredLines: [...currentUncoveredLines], + uncoveredBranches: [], + uncoveredFunctions: [...currentUncoveredFunctions], + }); + currentFile = null; + } + } + // Calculate overall metrics + const overall = { + statements: { + covered: totalLines.covered, + total: totalLines.total, + pct: totalLines.total > 0 ? (totalLines.covered / totalLines.total) * 100 : 100, + }, + branches: { + covered: totalBranches.covered, + total: totalBranches.total, + pct: totalBranches.total > 0 ? (totalBranches.covered / totalBranches.total) * 100 : 100, + }, + functions: { + covered: totalFunctions.covered, + total: totalFunctions.total, + pct: totalFunctions.total > 0 ? (totalFunctions.covered / totalFunctions.total) * 100 : 100, + }, + lines: { + covered: totalLines.covered, + total: totalLines.total, + pct: totalLines.total > 0 ? (totalLines.covered / totalLines.total) * 100 : 100, + }, + }; + return { + overall, + files, + uncoveredCode, + timestamp: new Date().toISOString(), + hasReport: true, + }; + } + catch (error) { + console.error('Error parsing LCOV report:', error); + return createEmptyAnalysis(); + } +} +// ========== ESLint Static Analysis ========== +/** + * Run ESLint on specified files or directory + */ +export async function runEslintAnalysis(targetPath, options = {}) { + try { + const eslintPath = path.join(targetPath, 'node_modules', '.bin', 'eslint'); + const hasEslint = fs.existsSync(eslintPath); + if (!hasEslint) { + console.log('ESLint not found in project, skipping static analysis'); + return createEmptyStaticAnalysis(); + } + const cmd = `${eslintPath} . --format json --ext .js,.jsx,.ts,.tsx 2>/dev/null || true`; + const { stdout } = await execAsync(cmd, { + cwd: targetPath, + maxBuffer: 10 * 1024 * 1024, // 10MB buffer + }); + if (!stdout.trim()) { + return createEmptyStaticAnalysis(); + } + const results = JSON.parse(stdout); + const issues = []; + let errors = 0; + let warnings = 0; + let info = 0; + let fixable = 0; + for (const file of results) { + for (const msg of file.messages) { + const severity = msg.severity === 2 ? 'error' : 'warning'; + issues.push({ + filePath: file.filePath, + line: msg.line, + column: msg.column, + severity, + ruleId: msg.ruleId || 'unknown', + message: msg.message, + suggestion: msg.fix ? 'Auto-fixable' : undefined, + }); + if (severity === 'error') + errors++; + else + warnings++; + if (msg.fix) + fixable++; + } + } + return { + issues, + summary: { errors, warnings, info, fixable }, + hasResults: issues.length > 0, + }; + } + catch (error) { + console.error('Error running ESLint:', error); + return createEmptyStaticAnalysis(); + } +} +// ========== Combined Analysis ========== +/** + * Get full coverage analysis from existing reports + */ +export function getCoverageAnalysis(repoPath = '.') { + const report = detectCoverageReport(repoPath); + if (!report.found || !report.path) { + return createEmptyAnalysis(); + } + switch (report.format) { + case 'json': + return parseCoverageJson(report.path); + case 'lcov': + return parseLcovReport(report.path); + default: + return createEmptyAnalysis(); + } +} +/** + * Run coverage analysis using nyc (generates report if needed) + */ +export async function runCoverageAnalysis(repoPath = '.', options = {}) { + // Check for existing report first + if (!options.regenerate) { + const existing = getCoverageAnalysis(repoPath); + if (existing.hasReport) { + return existing; + } + } + // Try to run coverage + try { + console.log('📊 Running coverage analysis...'); + // Check if nyc or jest --coverage is available + const packageJsonPath = path.join(repoPath, 'package.json'); + if (!fs.existsSync(packageJsonPath)) { + return createEmptyAnalysis(); + } + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); + const scripts = packageJson.scripts || {}; + let cmd = null; + if (scripts['test:coverage']) { + cmd = 'npm run test:coverage'; + } + else if (scripts['coverage']) { + cmd = 'npm run coverage'; + } + else if (scripts['test'] && packageJson.devDependencies?.jest) { + cmd = 'npm test -- --coverage --coverageReporters=json-summary'; + } + else if (packageJson.devDependencies?.nyc) { + cmd = 'npx nyc --reporter=json-summary npm test'; + } + if (cmd) { + console.log(` Running: ${cmd}`); + await execAsync(cmd, { cwd: repoPath, timeout: 300000 }); // 5 min timeout + return getCoverageAnalysis(repoPath); + } + return createEmptyAnalysis(); + } + catch (error) { + console.error('Coverage analysis failed:', error); + return createEmptyAnalysis(); + } +} +/** + * Get files with low coverage that need test suggestions + */ +export function getLowCoverageFiles(analysis, threshold = 50) { + return analysis.files.filter(f => f.metrics.lines.pct < threshold); +} +/** + * Format coverage analysis for CLI output + */ +export function formatCoverageReport(analysis) { + if (!analysis.hasReport) { + return '📊 No coverage report found. Run tests with coverage to generate one.'; + } + const lines = []; + lines.push('📊 Coverage Summary'); + lines.push('═'.repeat(50)); + lines.push(` Statements: ${analysis.overall.statements.pct.toFixed(1)}% (${analysis.overall.statements.covered}/${analysis.overall.statements.total})`); + lines.push(` Branches: ${analysis.overall.branches.pct.toFixed(1)}% (${analysis.overall.branches.covered}/${analysis.overall.branches.total})`); + lines.push(` Functions: ${analysis.overall.functions.pct.toFixed(1)}% (${analysis.overall.functions.covered}/${analysis.overall.functions.total})`); + lines.push(` Lines: ${analysis.overall.lines.pct.toFixed(1)}% (${analysis.overall.lines.covered}/${analysis.overall.lines.total})`); + const lowCoverage = getLowCoverageFiles(analysis, 50); + if (lowCoverage.length > 0) { + lines.push(''); + lines.push('⚠️ Files with low coverage (<50%):'); + for (const file of lowCoverage.slice(0, 10)) { + const shortPath = file.path.split('/').slice(-2).join('/'); + lines.push(` ${shortPath}: ${file.metrics.lines.pct.toFixed(1)}%`); + } + if (lowCoverage.length > 10) { + lines.push(` ... and ${lowCoverage.length - 10} more files`); + } + } + if (analysis.uncoveredCode.length > 0) { + lines.push(''); + lines.push('🔍 Uncovered code suggestions:'); + for (const item of analysis.uncoveredCode.slice(0, 5)) { + lines.push(` ${item.suggestion || 'Needs test coverage'}`); + } + } + return lines.join('\n'); +} +/** + * Format static analysis for CLI output + */ +export function formatStaticAnalysis(analysis) { + if (!analysis.hasResults) { + return '✅ No static analysis issues found.'; + } + const lines = []; + lines.push('🔬 Static Analysis Summary'); + lines.push('═'.repeat(50)); + lines.push(` Errors: ${analysis.summary.errors}`); + lines.push(` Warnings: ${analysis.summary.warnings}`); + lines.push(` Fixable: ${analysis.summary.fixable}`); + if (analysis.issues.length > 0) { + lines.push(''); + lines.push('Top issues:'); + for (const issue of analysis.issues.slice(0, 5)) { + const shortPath = issue.filePath.split('/').slice(-2).join('/'); + const icon = issue.severity === 'error' ? '❌' : '⚠️'; + lines.push(` ${icon} ${shortPath}:${issue.line} - ${issue.message}`); + } + } + return lines.join('\n'); +} +// ========== Helper Functions ========== +function createEmptyMetrics() { + return { + statements: { covered: 0, total: 0, pct: 0 }, + branches: { covered: 0, total: 0, pct: 0 }, + functions: { covered: 0, total: 0, pct: 0 }, + lines: { covered: 0, total: 0, pct: 0 }, + }; +} +function createEmptyAnalysis() { + return { + overall: createEmptyMetrics(), + files: [], + uncoveredCode: [], + timestamp: new Date().toISOString(), + hasReport: false, + }; +} +function createEmptyStaticAnalysis() { + return { + issues: [], + summary: { errors: 0, warnings: 0, info: 0, fixable: 0 }, + hasResults: false, + }; +} +//# sourceMappingURL=coverage-analyzer.js.map \ No newline at end of file diff --git a/dist/tools/coverage-analyzer.js.map b/dist/tools/coverage-analyzer.js.map new file mode 100644 index 0000000..2937b0a --- /dev/null +++ b/dist/tools/coverage-analyzer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"coverage-analyzer.js","sourceRoot":"","sources":["../../src/tools/coverage-analyzer.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/coverage-reporter.d.ts b/dist/tools/coverage-reporter.d.ts new file mode 100644 index 0000000..566d9f6 --- /dev/null +++ b/dist/tools/coverage-reporter.d.ts @@ -0,0 +1,46 @@ +/** + * Coverage Reporter Tool for PR Analysis + * Reads coverage reports and extracts metrics when coverage tool is configured + */ +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +import { CoverageReport } from '../types/agent.types.js'; +/** + * Detect if coverage tool is configured in the project + */ +export declare function detectCoverageTool(repoPath?: string): { + tool: string | null; + configured: boolean; + coveragePath?: string; +}; +/** + * Find existing coverage report files + */ +export declare function findCoverageFiles(repoPath?: string): string[]; +/** + * Read and parse coverage report + */ +export declare function readCoverageReport(repoPath?: string): CoverageReport; +/** + * Create coverage reporter tool + */ +export declare function createCoverageReporterTool(): DynamicStructuredTool; + forceRead: z.ZodOptional; +}, "strip", z.ZodTypeAny, { + repoPath?: string | undefined; + forceRead?: boolean | undefined; +}, { + repoPath?: string | undefined; + forceRead?: boolean | undefined; +}>, { + repoPath?: string; + forceRead?: boolean; +}, { + repoPath?: string | undefined; + forceRead?: boolean | undefined; +}, string, "report_coverage">; +/** + * Format coverage report for display + */ +export declare function formatCoverageReport(report: CoverageReport): string; diff --git a/dist/tools/coverage-reporter.js b/dist/tools/coverage-reporter.js new file mode 100644 index 0000000..480af01 --- /dev/null +++ b/dist/tools/coverage-reporter.js @@ -0,0 +1,306 @@ +/** + * Coverage Reporter Tool for PR Analysis + * Reads coverage reports and extracts metrics when coverage tool is configured + */ +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +import fs from 'node:fs'; +import path from 'node:path'; +// Common coverage file locations +const COVERAGE_PATHS = { + jest: ['coverage/coverage-summary.json', 'coverage/lcov.info', 'coverage/coverage-final.json'], + nyc: ['coverage/coverage-summary.json', '.nyc_output/coverage.json', 'coverage/lcov.info'], + vitest: ['coverage/coverage-summary.json', 'coverage/lcov.info'], + pytest: ['coverage.xml', 'htmlcov/coverage.json', '.coverage'], + generic: ['coverage.json', 'coverage/lcov.info', 'coverage.xml'], +}; +/** + * Detect if coverage tool is configured in the project + */ +export function detectCoverageTool(repoPath = '.') { + const packageJsonPath = path.join(repoPath, 'package.json'); + // Check for Node.js project with coverage config + if (fs.existsSync(packageJsonPath)) { + try { + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); + // Check Jest config + if (packageJson.jest?.collectCoverage || packageJson.jest?.coverageDirectory) { + return { tool: 'jest', configured: true }; + } + // Check for coverage scripts + const scripts = packageJson.scripts || {}; + const hasCoverageScript = Object.values(scripts).some((script) => typeof script === 'string' && (script.includes('--coverage') || script.includes('nyc'))); + if (hasCoverageScript) { + // Determine which tool + const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }; + if (deps.jest) + return { tool: 'jest', configured: true }; + if (deps.nyc || deps['istanbul']) + return { tool: 'nyc', configured: true }; + if (deps.vitest) + return { tool: 'vitest', configured: true }; + if (deps.c8) + return { tool: 'c8', configured: true }; + return { tool: 'node', configured: true }; + } + } + catch (e) { + // Ignore parse errors + } + } + // Check for Jest config file + if (fs.existsSync(path.join(repoPath, 'jest.config.js')) || fs.existsSync(path.join(repoPath, 'jest.config.ts'))) { + try { + const configPath = fs.existsSync(path.join(repoPath, 'jest.config.js')) + ? path.join(repoPath, 'jest.config.js') + : path.join(repoPath, 'jest.config.ts'); + const content = fs.readFileSync(configPath, 'utf-8'); + if (content.includes('collectCoverage') || content.includes('coverageDirectory')) { + return { tool: 'jest', configured: true }; + } + } + catch (e) { + // Ignore read errors + } + } + // Check for Python coverage + const setupCfg = path.join(repoPath, 'setup.cfg'); + const pyprojectToml = path.join(repoPath, 'pyproject.toml'); + if (fs.existsSync(setupCfg)) { + try { + const content = fs.readFileSync(setupCfg, 'utf-8'); + if (content.includes('[coverage:') || content.includes('coverage')) { + return { tool: 'pytest-cov', configured: true }; + } + } + catch (e) { + // Ignore read errors + } + } + if (fs.existsSync(pyprojectToml)) { + try { + const content = fs.readFileSync(pyprojectToml, 'utf-8'); + if (content.includes('[tool.coverage]') || content.includes('pytest-cov')) { + return { tool: 'pytest-cov', configured: true }; + } + } + catch (e) { + // Ignore read errors + } + } + return { tool: null, configured: false }; +} +/** + * Find existing coverage report files + */ +export function findCoverageFiles(repoPath = '.') { + const foundFiles = []; + for (const paths of Object.values(COVERAGE_PATHS)) { + for (const coveragePath of paths) { + const fullPath = path.join(repoPath, coveragePath); + if (fs.existsSync(fullPath)) { + foundFiles.push(fullPath); + } + } + } + return [...new Set(foundFiles)]; // Remove duplicates +} +/** + * Parse Jest/NYC coverage-summary.json format + */ +function parseJestCoverageSummary(filePath) { + try { + const content = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + const total = content.total; + if (!total) + return null; + const fileBreakdown = []; + for (const [file, data] of Object.entries(content)) { + if (file === 'total') + continue; + const fileData = data; + fileBreakdown.push({ + file, + lineCoverage: fileData.lines?.pct || 0, + branchCoverage: fileData.branches?.pct, + }); + } + return { + available: true, + overallPercentage: total.lines?.pct || total.statements?.pct || 0, + lineCoverage: total.lines?.pct, + branchCoverage: total.branches?.pct, + fileBreakdown: fileBreakdown.slice(0, 20), // Limit to 20 files + coverageTool: 'jest/nyc', + }; + } + catch (e) { + return null; + } +} +/** + * Parse LCOV format + */ +function parseLcov(filePath) { + try { + const content = fs.readFileSync(filePath, 'utf-8'); + const files = []; + let currentFile = ''; + let linesHit = 0; + let linesTotal = 0; + for (const line of content.split('\n')) { + if (line.startsWith('SF:')) { + currentFile = line.substring(3); + linesHit = 0; + linesTotal = 0; + } + else if (line.startsWith('LH:')) { + linesHit = parseInt(line.substring(3), 10); + } + else if (line.startsWith('LF:')) { + linesTotal = parseInt(line.substring(3), 10); + } + else if (line === 'end_of_record' && currentFile) { + files.push({ file: currentFile, linesHit, linesTotal }); + currentFile = ''; + } + } + const totalHit = files.reduce((sum, f) => sum + f.linesHit, 0); + const totalLines = files.reduce((sum, f) => sum + f.linesTotal, 0); + const overallPercentage = totalLines > 0 ? (totalHit / totalLines) * 100 : 0; + return { + available: true, + overallPercentage: Math.round(overallPercentage * 100) / 100, + lineCoverage: overallPercentage, + fileBreakdown: files.slice(0, 20).map(f => ({ + file: f.file, + lineCoverage: f.linesTotal > 0 ? (f.linesHit / f.linesTotal) * 100 : 0, + })), + coverageTool: 'lcov', + }; + } + catch (e) { + return null; + } +} +/** + * Parse Cobertura XML format + */ +function parseCobertura(filePath) { + try { + const content = fs.readFileSync(filePath, 'utf-8'); + // Simple regex parsing for line-rate attribute + const lineRateMatch = content.match(/line-rate="([0-9.]+)"/); + const branchRateMatch = content.match(/branch-rate="([0-9.]+)"/); + if (!lineRateMatch) + return null; + const lineRate = parseFloat(lineRateMatch[1]) * 100; + const branchRate = branchRateMatch ? parseFloat(branchRateMatch[1]) * 100 : undefined; + return { + available: true, + overallPercentage: Math.round(lineRate * 100) / 100, + lineCoverage: lineRate, + branchCoverage: branchRate, + coverageTool: 'cobertura', + }; + } + catch (e) { + return null; + } +} +/** + * Read and parse coverage report + */ +export function readCoverageReport(repoPath = '.') { + const coverageFiles = findCoverageFiles(repoPath); + if (coverageFiles.length === 0) { + return { available: false }; + } + // Try to parse each file type + for (const filePath of coverageFiles) { + const fileName = path.basename(filePath); + if (fileName === 'coverage-summary.json' || fileName === 'coverage.json') { + const report = parseJestCoverageSummary(filePath); + if (report) + return report; + } + if (fileName === 'lcov.info' || fileName.endsWith('.lcov')) { + const report = parseLcov(filePath); + if (report) + return report; + } + if (fileName === 'coverage.xml' || fileName.endsWith('cobertura.xml')) { + const report = parseCobertura(filePath); + if (report) + return report; + } + } + return { available: false }; +} +/** + * Create coverage reporter tool + */ +export function createCoverageReporterTool() { + return new DynamicStructuredTool({ + name: 'report_coverage', + description: 'Read test coverage reports and extract metrics (only if coverage tool is configured)', + schema: z.object({ + repoPath: z.string().optional().describe('Repository path to check for coverage'), + forceRead: z.boolean().optional().describe('Force reading coverage even if not configured'), + }), + func: async ({ repoPath, forceRead }) => { + const projectPath = repoPath || '.'; + // Check if coverage tool is configured + const toolConfig = detectCoverageTool(projectPath); + if (!toolConfig.configured && !forceRead) { + return JSON.stringify({ + available: false, + reason: 'No coverage tool configured in project', + configured: false, + }); + } + // Try to read coverage report + const report = readCoverageReport(projectPath); + return JSON.stringify({ + ...report, + configured: toolConfig.configured, + tool: toolConfig.tool, + }); + }, + }); +} +/** + * Format coverage report for display + */ +export function formatCoverageReport(report) { + if (!report.available) { + return 'No coverage data available'; + } + let output = ''; + if (report.overallPercentage !== undefined) { + const emoji = report.overallPercentage >= 80 ? '🟢' : report.overallPercentage >= 60 ? '🟡' : '🔴'; + output += `${emoji} Overall Coverage: ${report.overallPercentage.toFixed(1)}%\n`; + } + if (report.lineCoverage !== undefined) { + output += ` Lines: ${report.lineCoverage.toFixed(1)}%\n`; + } + if (report.branchCoverage !== undefined) { + output += ` Branches: ${report.branchCoverage.toFixed(1)}%\n`; + } + if (report.delta !== undefined) { + const deltaEmoji = report.delta >= 0 ? '📈' : '📉'; + output += `${deltaEmoji} Coverage Delta: ${report.delta >= 0 ? '+' : ''}${report.delta.toFixed(1)}%\n`; + } + if (report.fileBreakdown && report.fileBreakdown.length > 0) { + output += '\nFile Breakdown:\n'; + for (const file of report.fileBreakdown.slice(0, 10)) { + const emoji = file.lineCoverage >= 80 ? '✅' : file.lineCoverage >= 60 ? '⚠️' : '❌'; + output += ` ${emoji} ${path.basename(file.file)}: ${file.lineCoverage.toFixed(1)}%\n`; + } + if (report.fileBreakdown.length > 10) { + output += ` ... and ${report.fileBreakdown.length - 10} more files\n`; + } + } + return output; +} +//# sourceMappingURL=coverage-reporter.js.map \ No newline at end of file diff --git a/dist/tools/coverage-reporter.js.map b/dist/tools/coverage-reporter.js.map new file mode 100644 index 0000000..a00facb --- /dev/null +++ b/dist/tools/coverage-reporter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"coverage-reporter.js","sourceRoot":"","sources":["../../src/tools/coverage-reporter.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/devops-cost-estimator.d.ts b/dist/tools/devops-cost-estimator.d.ts new file mode 100644 index 0000000..00a2066 --- /dev/null +++ b/dist/tools/devops-cost-estimator.d.ts @@ -0,0 +1,99 @@ +/** + * DevOps Cost Estimator Tool for PR Analysis + * Estimates AWS infrastructure costs for DevOps-related changes (IaC, Dockerfiles, etc.) + * Uses MCP to connect to AWS for cost estimation when available + */ +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +import { DevOpsCostEstimate } from '../types/agent.types.js'; +/** + * Check if a file is a DevOps-related file + */ +export declare function isDevOpsFile(filePath: string): { + isDevOps: boolean; + type: string | null; +}; +/** + * Analyze DevOps files and estimate costs + */ +export declare function analyzeDevOpsFiles(files: Array<{ + path: string; + diff: string; +}>): { + hasDevOpsChanges: boolean; + fileTypes: string[]; + estimates: DevOpsCostEstimate[]; + totalEstimatedCost: number; +}; +/** + * Create DevOps cost estimator tool + */ +export declare function createDevOpsCostEstimatorTool(): DynamicStructuredTool, "many">; + awsCredentials: z.ZodOptional; + secretAccessKey: z.ZodOptional; + region: z.ZodOptional; + }, "strip", z.ZodTypeAny, { + accessKeyId?: string | undefined; + secretAccessKey?: string | undefined; + region?: string | undefined; + }, { + accessKeyId?: string | undefined; + secretAccessKey?: string | undefined; + region?: string | undefined; + }>>; +}, "strip", z.ZodTypeAny, { + files: { + path: string; + diff: string; + }[]; + awsCredentials?: { + accessKeyId?: string | undefined; + secretAccessKey?: string | undefined; + region?: string | undefined; + } | undefined; +}, { + files: { + path: string; + diff: string; + }[]; + awsCredentials?: { + accessKeyId?: string | undefined; + secretAccessKey?: string | undefined; + region?: string | undefined; + } | undefined; +}>, { + files: Array<{ + path: string; + diff: string; + }>; + awsCredentials?: { + accessKeyId?: string; + secretAccessKey?: string; + region?: string; + }; +}, { + files: { + path: string; + diff: string; + }[]; + awsCredentials?: { + accessKeyId?: string | undefined; + secretAccessKey?: string | undefined; + region?: string | undefined; + } | undefined; +}, string, "estimate_devops_costs">; +/** + * Format cost estimates for display + */ +export declare function formatCostEstimates(estimates: DevOpsCostEstimate[], totalCost: number): string; diff --git a/dist/tools/devops-cost-estimator.js b/dist/tools/devops-cost-estimator.js new file mode 100644 index 0000000..cf79508 --- /dev/null +++ b/dist/tools/devops-cost-estimator.js @@ -0,0 +1,354 @@ +/** + * DevOps Cost Estimator Tool for PR Analysis + * Estimates AWS infrastructure costs for DevOps-related changes (IaC, Dockerfiles, etc.) + * Uses MCP to connect to AWS for cost estimation when available + */ +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +// DevOps file patterns +const DEVOPS_PATTERNS = { + terraform: [/\.tf$/, /\.tfvars$/], + cloudformation: [/template\.(yaml|yml|json)$/, /cloudformation\.(yaml|yml|json)$/], + cdk: [/cdk\.json$/, /\.ts$.*cdk/], + pulumi: [/Pulumi\.(yaml|yml)$/, /pulumi\..*\.(ts|js|py|go)$/], + docker: [/Dockerfile/, /docker-compose\.(yaml|yml)$/], + kubernetes: [/k8s.*\.(yaml|yml)$/, /kubernetes.*\.(yaml|yml)$/, /\.kube.*\.(yaml|yml)$/], + github_actions: [/\.github\/workflows\/.*\.(yaml|yml)$/], + serverless: [/serverless\.(yaml|yml|json)$/], +}; +// AWS resource cost estimates (monthly USD, approximate) +const AWS_RESOURCE_COSTS = { + 'ec2-t3.micro': { min: 8, typical: 8.5, max: 10 }, + 'ec2-t3.small': { min: 15, typical: 17, max: 20 }, + 'ec2-t3.medium': { min: 30, typical: 34, max: 40 }, + 'ec2-t3.large': { min: 60, typical: 68, max: 80 }, + 'ec2-m5.large': { min: 70, typical: 80, max: 95 }, + 'ec2-m5.xlarge': { min: 140, typical: 160, max: 190 }, + 'lambda-1m-invocations': { min: 0.2, typical: 0.4, max: 2 }, + 'lambda-10m-invocations': { min: 2, typical: 4, max: 20 }, + 's3-storage-gb': { min: 0.023, typical: 0.023, max: 0.025 }, + 's3-requests-1k': { min: 0.004, typical: 0.005, max: 0.006 }, + 'rds-db.t3.micro': { min: 13, typical: 15, max: 18 }, + 'rds-db.t3.small': { min: 26, typical: 30, max: 35 }, + 'rds-db.t3.medium': { min: 52, typical: 60, max: 70 }, + 'rds-db.m5.large': { min: 140, typical: 160, max: 190 }, + 'ecs-task-256cpu-512mem': { min: 10, typical: 12, max: 15 }, + 'ecs-task-512cpu-1024mem': { min: 20, typical: 24, max: 30 }, + 'ecs-task-1024cpu-2048mem': { min: 40, typical: 48, max: 60 }, + 'alb': { min: 16, typical: 22, max: 30 }, + 'nat-gateway': { min: 32, typical: 45, max: 60 }, + 'elasticache-t3.micro': { min: 12, typical: 15, max: 18 }, + 'cloudfront-1tb': { min: 85, typical: 100, max: 120 }, + 'api-gateway-1m-requests': { min: 3.5, typical: 4, max: 5 }, + 'sqs-1m-requests': { min: 0.4, typical: 0.5, max: 0.6 }, + 'sns-1m-notifications': { min: 0.5, typical: 0.6, max: 0.7 }, + 'dynamodb-25wcu-25rcu': { min: 25, typical: 30, max: 40 }, +}; +/** + * Check if a file is a DevOps-related file + */ +export function isDevOpsFile(filePath) { + for (const [type, patterns] of Object.entries(DEVOPS_PATTERNS)) { + for (const pattern of patterns) { + if (pattern.test(filePath)) { + return { isDevOps: true, type }; + } + } + } + return { isDevOps: false, type: null }; +} +/** + * Extract AWS resources from Terraform content + */ +function extractTerraformResources(content) { + const resources = []; + // Match resource blocks - handles both regular files and diff format (with + prefix) + const resourceRegex = /^[\+\s]*resource\s+"([^"]+)"\s+"([^"]+)"/gm; + let match; + console.error(`[DevOps] Extracting Terraform resources from content length: ${content.length}`); + console.error(`[DevOps] First 200 chars: ${content.substring(0, 200)}`); + while ((match = resourceRegex.exec(content)) !== null) { + const resourceType = match[1]; + const resourceName = match[2]; + console.error(`[DevOps] Found resource: ${resourceType} "${resourceName}"`); + // Map Terraform resources to our cost categories + if (resourceType.startsWith('aws_instance')) { + resources.push({ resource: resourceName, type: 'ec2' }); + } + else if (resourceType.startsWith('aws_lambda')) { + resources.push({ resource: resourceName, type: 'lambda' }); + } + else if (resourceType.startsWith('aws_s3')) { + resources.push({ resource: resourceName, type: 's3' }); + } + else if (resourceType.startsWith('aws_rds') || resourceType.startsWith('aws_db')) { + resources.push({ resource: resourceName, type: 'rds' }); + } + else if (resourceType.startsWith('aws_ecs')) { + resources.push({ resource: resourceName, type: 'ecs' }); + } + else if (resourceType.startsWith('aws_alb') || resourceType.startsWith('aws_lb')) { + resources.push({ resource: resourceName, type: 'alb' }); + } + else if (resourceType.startsWith('aws_nat')) { + resources.push({ resource: resourceName, type: 'nat-gateway' }); + } + else if (resourceType.startsWith('aws_elasticache')) { + resources.push({ resource: resourceName, type: 'elasticache' }); + } + else if (resourceType.startsWith('aws_cloudfront')) { + resources.push({ resource: resourceName, type: 'cloudfront' }); + } + else if (resourceType.startsWith('aws_api_gateway') || resourceType.startsWith('aws_apigatewayv2')) { + resources.push({ resource: resourceName, type: 'api-gateway' }); + } + else if (resourceType.startsWith('aws_sqs')) { + resources.push({ resource: resourceName, type: 'sqs' }); + } + else if (resourceType.startsWith('aws_sns')) { + resources.push({ resource: resourceName, type: 'sns' }); + } + else if (resourceType.startsWith('aws_dynamodb')) { + resources.push({ resource: resourceName, type: 'dynamodb' }); + } + } + console.error(`[DevOps] Extracted ${resources.length} Terraform resources`); + return resources; +} +/** + * Extract AWS resources from CloudFormation content + */ +function extractCloudFormationResources(content) { + const resources = []; + // Simple pattern matching for CFN resources + const typeMap = { + 'AWS::EC2::Instance': 'ec2', + 'AWS::Lambda::Function': 'lambda', + 'AWS::S3::Bucket': 's3', + 'AWS::RDS::DBInstance': 'rds', + 'AWS::ECS::Service': 'ecs', + 'AWS::ECS::TaskDefinition': 'ecs', + 'AWS::ElasticLoadBalancingV2::LoadBalancer': 'alb', + 'AWS::EC2::NatGateway': 'nat-gateway', + 'AWS::ElastiCache::CacheCluster': 'elasticache', + 'AWS::CloudFront::Distribution': 'cloudfront', + 'AWS::ApiGateway::RestApi': 'api-gateway', + 'AWS::ApiGatewayV2::Api': 'api-gateway', + 'AWS::SQS::Queue': 'sqs', + 'AWS::SNS::Topic': 'sns', + 'AWS::DynamoDB::Table': 'dynamodb', + }; + for (const [awsType, costType] of Object.entries(typeMap)) { + if (content.includes(awsType)) { + // Try to extract logical ID + const regex = new RegExp(`(\\w+):\\s*\\n\\s*Type:\\s*['"]?${awsType.replace(/::/g, '::')}`, 'g'); + const matches = content.matchAll(regex); + for (const match of matches) { + resources.push({ resource: match[1] || costType, type: costType }); + } + // Fallback if no match found but type exists + if (resources.filter(r => r.type === costType).length === 0) { + resources.push({ resource: costType, type: costType }); + } + } + } + return resources; +} +/** + * Estimate cost for a resource type + */ +function estimateResourceCost(resourceType) { + // Find matching cost entry + let costKey = ''; + let confidence = 'low'; + switch (resourceType) { + case 'ec2': + costKey = 'ec2-t3.medium'; + confidence = 'medium'; + break; + case 'lambda': + costKey = 'lambda-1m-invocations'; + confidence = 'low'; + break; + case 's3': + costKey = 's3-storage-gb'; + confidence = 'low'; + break; + case 'rds': + costKey = 'rds-db.t3.small'; + confidence = 'medium'; + break; + case 'ecs': + costKey = 'ecs-task-512cpu-1024mem'; + confidence = 'medium'; + break; + case 'alb': + costKey = 'alb'; + confidence = 'high'; + break; + case 'nat-gateway': + costKey = 'nat-gateway'; + confidence = 'high'; + break; + case 'elasticache': + costKey = 'elasticache-t3.micro'; + confidence = 'medium'; + break; + case 'cloudfront': + costKey = 'cloudfront-1tb'; + confidence = 'low'; + break; + case 'api-gateway': + costKey = 'api-gateway-1m-requests'; + confidence = 'low'; + break; + case 'sqs': + costKey = 'sqs-1m-requests'; + confidence = 'low'; + break; + case 'sns': + costKey = 'sns-1m-notifications'; + confidence = 'low'; + break; + case 'dynamodb': + costKey = 'dynamodb-25wcu-25rcu'; + confidence = 'low'; + break; + default: + return { + resource: resourceType, + resourceType, + estimatedNewCost: 0, + confidence: 'low', + details: 'Unknown resource type - manual estimation required', + }; + } + const cost = AWS_RESOURCE_COSTS[costKey]; + if (!cost) { + return { + resource: resourceType, + resourceType, + estimatedNewCost: 0, + confidence: 'low', + details: 'Cost data not available', + }; + } + return { + resource: resourceType, + resourceType, + estimatedNewCost: cost.typical, + confidence, + details: `Estimated $${cost.min.toFixed(2)} - $${cost.max.toFixed(2)}/month`, + }; +} +/** + * Analyze DevOps files and estimate costs + */ +export function analyzeDevOpsFiles(files) { + console.error(`[DevOps] Analyzing ${files.length} files`); + const devOpsFiles = files.filter(f => isDevOpsFile(f.path).isDevOps); + console.error(`[DevOps] Found ${devOpsFiles.length} DevOps files:`, devOpsFiles.map(f => f.path)); + if (devOpsFiles.length === 0) { + return { + hasDevOpsChanges: false, + fileTypes: [], + estimates: [], + totalEstimatedCost: 0, + }; + } + const fileTypes = new Set(); + const allResources = []; + for (const file of devOpsFiles) { + const { type } = isDevOpsFile(file.path); + if (type) + fileTypes.add(type); + console.error(`[DevOps] Processing file: ${file.path} (type: ${type})`); + // Get the full content (in real scenario, we'd read the file) + // For now, analyze the diff + const content = file.diff; + if (type === 'terraform') { + allResources.push(...extractTerraformResources(content)); + } + else if (type === 'cloudformation') { + allResources.push(...extractCloudFormationResources(content)); + } + // Add more extractors for other IaC types as needed + } + // Estimate costs for each resource + const estimates = []; + const seenTypes = new Set(); + console.error(`[DevOps] Total resources found: ${allResources.length}`); + for (const resource of allResources) { + if (!seenTypes.has(resource.type)) { + seenTypes.add(resource.type); + const estimate = estimateResourceCost(resource.type); + console.error(`[DevOps] Estimated cost for ${resource.type}: $${estimate.estimatedNewCost}/month`); + estimates.push(estimate); + } + } + const totalEstimatedCost = estimates.reduce((sum, e) => sum + e.estimatedNewCost, 0); + console.error(`[DevOps] Final: ${estimates.length} estimates, total: $${totalEstimatedCost}/month`); + return { + hasDevOpsChanges: true, + fileTypes: Array.from(fileTypes), + estimates, + totalEstimatedCost, + }; +} +/** + * Create DevOps cost estimator tool + */ +export function createDevOpsCostEstimatorTool() { + return new DynamicStructuredTool({ + name: 'estimate_devops_costs', + description: 'Analyze DevOps/IaC files and estimate AWS infrastructure costs', + schema: z.object({ + files: z.array(z.object({ + path: z.string(), + diff: z.string(), + })).describe('Array of changed files to analyze'), + awsCredentials: z.object({ + accessKeyId: z.string().optional(), + secretAccessKey: z.string().optional(), + region: z.string().optional(), + }).optional().describe('AWS credentials for live cost lookup (optional)'), + }), + func: async ({ files }) => { + const analysis = analyzeDevOpsFiles(files); + if (!analysis.hasDevOpsChanges) { + return JSON.stringify({ + hasDevOpsChanges: false, + message: 'No DevOps/IaC files detected in changes', + }); + } + return JSON.stringify({ + hasDevOpsChanges: true, + fileTypes: analysis.fileTypes, + estimates: analysis.estimates, + totalEstimatedCost: analysis.totalEstimatedCost, + message: `Detected ${analysis.fileTypes.join(', ')} changes. Estimated monthly cost impact: $${analysis.totalEstimatedCost.toFixed(2)}`, + disclaimer: 'Cost estimates are approximate and based on typical resource sizes. Actual costs depend on usage patterns, region, and specific configurations.', + }); + }, + }); +} +/** + * Format cost estimates for display + */ +export function formatCostEstimates(estimates, totalCost) { + if (estimates.length === 0) { + return 'No cost estimates available'; + } + let output = '💰 AWS Cost Estimates\n\n'; + for (const estimate of estimates) { + const emoji = estimate.confidence === 'high' ? '🟢' : estimate.confidence === 'medium' ? '🟡' : '🔴'; + output += `${emoji} ${estimate.resourceType.toUpperCase()}: ~$${estimate.estimatedNewCost.toFixed(2)}/month\n`; + if (estimate.details) { + output += ` ${estimate.details}\n`; + } + } + output += `\n📊 Total Estimated Impact: ~$${totalCost.toFixed(2)}/month\n`; + output += '\n⚠️ Estimates are approximate. Actual costs depend on usage and configuration.\n'; + return output; +} +//# sourceMappingURL=devops-cost-estimator.js.map \ No newline at end of file diff --git a/dist/tools/devops-cost-estimator.js.map b/dist/tools/devops-cost-estimator.js.map new file mode 100644 index 0000000..ad7487d --- /dev/null +++ b/dist/tools/devops-cost-estimator.js.map @@ -0,0 +1 @@ +{"version":3,"file":"devops-cost-estimator.js","sourceRoot":"","sources":["../../src/tools/devops-cost-estimator.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/helpers.d.ts b/dist/tools/helpers.d.ts deleted file mode 100644 index 7da4ea9..0000000 --- a/dist/tools/helpers.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Helper functions for file analysis tools - */ -import type { DiffFile, AgentState } from '../pr-agent'; -import type { AnalysisResponse } from '../providers/types'; -export declare function prepareFileContent(file: DiffFile, getFileContent: (filePath: string, ref?: string) => string | null, getDeletedFileContent: (filePath: string, ref?: string) => string | null): { - fileContent: string; - analysisContext: string; -}; -export declare function extractRisksAndComplexity(rawResponse: string, analysis: AnalysisResponse, state: AgentState): void; -export declare function checkImportsForFile(file: DiffFile, githubApi: any, repository: { - owner: string; - repo: string; - baseSha?: string; - headSha?: string; -} | undefined, state: AgentState): Promise<{ - importFindings: any[]; - risksFromImports: string[]; -}>; diff --git a/dist/tools/helpers.js b/dist/tools/helpers.js deleted file mode 100644 index 3720b52..0000000 --- a/dist/tools/helpers.js +++ /dev/null @@ -1,89 +0,0 @@ -"use strict"; -/** - * Helper functions for file analysis tools - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.prepareFileContent = prepareFileContent; -exports.extractRisksAndComplexity = extractRisksAndComplexity; -exports.checkImportsForFile = checkImportsForFile; -const import_checker_1 = require("./import-checker"); -function prepareFileContent(file, getFileContent, getDeletedFileContent) { - let fileContent = ''; - let analysisContext = ''; - if (file.status === 'A') { - const fullContent = getFileContent(file.path); - if (fullContent) { - fileContent = fullContent; - analysisContext = `This is a NEW FILE being added to the repository. Analyze the entire file content for:\n`; - } - else { - fileContent = file.diff; - analysisContext = `This is a NEW FILE being added (full content not available, showing diff). Analyze it for:\n`; - } - } - else if (file.status === 'D') { - const deletedContent = getDeletedFileContent(file.path); - if (deletedContent) { - fileContent = `=== DELETED FILE CONTENT ===\n${deletedContent}\n=== END DELETED FILE ===\n\n=== DIFF SHOWING DELETION ===\n${file.diff}`; - analysisContext = `This file is being DELETED. Analyze:\n1. What functionality is being removed\n2. If this deletion will break any dependencies\n3. Whether other files import or depend on this file\n4. If tests or documentation need updating\n5. Overall impact on the codebase\n\n`; - } - else { - fileContent = file.diff; - analysisContext = `This file is being DELETED (full content not available, showing diff). Analyze the deletion impact:\n`; - } - } - else { - fileContent = file.diff; - analysisContext = `This is a MODIFIED FILE. Analyze the changes shown in the diff for:\n`; - } - return { fileContent, analysisContext }; -} -function extractRisksAndComplexity(rawResponse, analysis, state) { - const risksMatch = rawResponse.match(/(?:###\s*)?(?:Potential\s+)?Risks?:?\s*\n(.*?)(?=\n(?:###|Complexity:|$))/is); - if (risksMatch && risksMatch[1]) { - const risksText = risksMatch[1].trim(); - if (!risksText.toLowerCase().includes('none') && !risksText.toLowerCase().includes('no risks')) { - risksText.split('\n').forEach(line => { - const trimmed = line.trim(); - if (trimmed && (trimmed.startsWith('- ') || trimmed.startsWith('* ') || trimmed.startsWith('• ') || trimmed.match(/^\d+\.\s+/))) { - const riskText = trimmed.replace(/^[-*•]\s+/, '').replace(/^\d+\.\s+/, '').trim(); - if (riskText && !riskText.toLowerCase().includes('none')) { - analysis.risks.push(riskText); - state.risks.add(riskText); - } - } - }); - } - } - const complexityMatch = rawResponse.match(/Complexity:?\s*(\d+)/i); - if (complexityMatch && complexityMatch[1]) { - const parsed = parseInt(complexityMatch[1]); - if (!isNaN(parsed) && parsed >= 1 && parsed <= 5) { - analysis.complexity = parsed; - } - } -} -async function checkImportsForFile(file, githubApi, repository, state) { - const importFindings = []; - const risksFromImports = []; - if (githubApi && repository && (file.status === 'A' || file.status === 'M')) { - try { - const importCheck = await (0, import_checker_1.checkImportsAndUsages)(file, githubApi, repository); - if (importCheck.success && importCheck.findings) { - importFindings.push(...importCheck.findings); - importCheck.findings.forEach(finding => { - if (finding.type === 'missing_import' || finding.type === 'missing_export') { - const riskMsg = `[File: ${finding.file}] ${finding.message}${finding.line ? ` (line ${finding.line})` : ''}`; - state.risks.add(riskMsg); - risksFromImports.push(riskMsg); - } - }); - } - } - catch (error) { - // Silently fail - GitHub API check is optional - } - } - return { importFindings, risksFromImports }; -} -//# sourceMappingURL=helpers.js.map \ No newline at end of file diff --git a/dist/tools/helpers.js.map b/dist/tools/helpers.js.map deleted file mode 100644 index ec1257a..0000000 --- a/dist/tools/helpers.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/tools/helpers.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/import-checker.d.ts b/dist/tools/import-checker.d.ts deleted file mode 100644 index b4a081c..0000000 --- a/dist/tools/import-checker.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Import checker utility - checks imports and usages using GitHub API - */ -import type { DiffFile } from '../pr-agent'; -export declare function checkImportsAndUsages(file: DiffFile, githubApi: any, repository: { - owner: string; - repo: string; - baseSha?: string; - headSha?: string; -}): Promise<{ - success: boolean; - error?: string; - findings: any[]; -}>; diff --git a/dist/tools/import-checker.js b/dist/tools/import-checker.js deleted file mode 100644 index 319be69..0000000 --- a/dist/tools/import-checker.js +++ /dev/null @@ -1,180 +0,0 @@ -"use strict"; -/** - * Import checker utility - checks imports and usages using GitHub API - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.checkImportsAndUsages = checkImportsAndUsages; -async function checkImportsAndUsages(file, githubApi, repository) { - const findings = []; - try { - let fileContent = null; - const ref = repository.headSha || 'HEAD'; - try { - const { data } = await githubApi.rest.repos.getContent({ - owner: repository.owner, - repo: repository.repo, - path: file.path, - ref - }); - if (!Array.isArray(data) && data.type === 'file' && data.content) { - fileContent = Buffer.from(data.content, 'base64').toString('utf-8'); - } - } - catch (error) { - if (repository.baseSha) { - try { - const { data } = await githubApi.rest.repos.getContent({ - owner: repository.owner, - repo: repository.repo, - path: file.path, - ref: repository.baseSha - }); - if (!Array.isArray(data) && data.type === 'file' && data.content) { - fileContent = Buffer.from(data.content, 'base64').toString('utf-8'); - } - } - catch (e) { - // File doesn't exist - } - } - } - if (!fileContent) { - return { - success: true, - findings: [{ - type: 'missing_import', - file: file.path, - message: `Cannot validate imports: file content not available` - }] - }; - } - const importPatterns = [ - /import\s+(?:(?:\{([^}]*)\}|\*|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g, - /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g, - /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g - ]; - const imports = []; - let lineNum = 1; - for (const line of fileContent.split('\n')) { - for (const pattern of importPatterns) { - let match; - while ((match = pattern.exec(line)) !== null) { - const importPath = match[2] || match[1]; - if (importPath && (importPath.startsWith('.') || importPath.startsWith('/'))) { - const names = match[1] ? match[1].split(',').map(n => n.trim().replace(/as\s+\w+/, '').trim()) : undefined; - imports.push({ path: importPath, names, line: lineNum }); - } - } - } - lineNum++; - } - for (const imp of imports) { - const path = require('path'); - const baseDir = path.dirname(file.path); - let resolvedPath = path.resolve(baseDir, imp.path.replace(/\.(ts|tsx|js|jsx)$/, '')); - resolvedPath = resolvedPath.replace(/^.*\//, ''); - const extensions = ['.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js', '/index.jsx']; - let foundFile = false; - let importedFileContent = null; - for (const ext of extensions) { - const candidatePath = resolvedPath + ext; - try { - const { data } = await githubApi.rest.repos.getContent({ - owner: repository.owner, - repo: repository.repo, - path: candidatePath, - ref - }); - if (!Array.isArray(data) && data.type === 'file' && data.content) { - importedFileContent = Buffer.from(data.content, 'base64').toString('utf-8'); - foundFile = true; - break; - } - } - catch (error) { - if (repository.baseSha) { - try { - const { data } = await githubApi.rest.repos.getContent({ - owner: repository.owner, - repo: repository.repo, - path: candidatePath, - ref: repository.baseSha - }); - if (!Array.isArray(data) && data.type === 'file' && data.content) { - importedFileContent = Buffer.from(data.content, 'base64').toString('utf-8'); - foundFile = true; - break; - } - } - catch (e) { - // Continue to next candidate - } - } - } - } - if (!foundFile) { - findings.push({ - type: 'missing_import', - file: file.path, - import: imp.path, - line: imp.line, - message: `Import '${imp.path}' not found in repository` - }); - continue; - } - if (imp.names && importedFileContent) { - for (const name of imp.names) { - const cleanName = name.trim(); - const exportPatterns = [ - new RegExp(`export\\s+(?:const|let|var|function|class|type|interface|enum)\\s+${cleanName}\\b`), - new RegExp(`export\\s*\\{[^}]*\\b${cleanName}\\b[^}]*\\}`), - new RegExp(`export\\s+default\\s+${cleanName}\\b`) - ]; - const isExported = exportPatterns.some(pattern => pattern.test(importedFileContent)); - if (!isExported) { - findings.push({ - type: 'missing_export', - file: file.path, - import: imp.path, - export: cleanName, - line: imp.line, - message: `'${cleanName}' is imported from '${imp.path}' but not exported` - }); - } - } - } - } - if (fileContent) { - for (const imp of imports) { - if (imp.names && imp.names.length > 0) { - for (const name of imp.names) { - const cleanName = name.trim(); - const afterImport = fileContent.split('\n').slice(imp.line).join('\n'); - const usageCount = (afterImport.match(new RegExp(`\\b${cleanName}\\b`, 'g')) || []).length; - if (usageCount <= 1) { - findings.push({ - type: 'unused_import', - file: file.path, - import: cleanName, - line: imp.line, - message: `'${cleanName}' is imported but never used` - }); - } - } - } - } - } - return { - success: true, - findings - }; - } - catch (error) { - return { - success: false, - error: error.message, - findings: [] - }; - } -} -//# sourceMappingURL=import-checker.js.map \ No newline at end of file diff --git a/dist/tools/import-checker.js.map b/dist/tools/import-checker.js.map deleted file mode 100644 index 270e131..0000000 --- a/dist/tools/import-checker.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"import-checker.js","sourceRoot":"","sources":["../../src/tools/import-checker.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/index.d.ts b/dist/tools/index.d.ts index f37318c..42ed49e 100644 --- a/dist/tools/index.d.ts +++ b/dist/tools/index.d.ts @@ -2,3 +2,10 @@ * Export all PR analysis tools */ export { parseDiff, createFileAnalyzerTool, createRiskDetectorTool, createComplexityScorerTool, createSummaryGeneratorTool, createCodeSuggestionTool, } from './pr-analysis-tools.js'; +export { detectTestFramework, isTestFile, isCodeFile, suggestTestFilePath, createTestSuggestionTool, generateTestTemplate, analyzeTestQuality, formatTestEnhancement, } from './test-suggestion-tool.js'; +export type { TestEnhancement } from './test-suggestion-tool.js'; +export { detectCoverageTool, findCoverageFiles, readCoverageReport, createCoverageReporterTool, formatCoverageReport, } from './coverage-reporter.js'; +export { isDevOpsFile, analyzeDevOpsFiles, createDevOpsCostEstimatorTool, formatCostEstimates, } from './devops-cost-estimator.js'; +export { classifyProject, createProjectClassifierTool, formatClassification, } from './project-classifier.js'; +export { getCoverageAnalysis, runCoverageAnalysis, runEslintAnalysis, getLowCoverageFiles, detectCoverageReport, parseCoverageJson, parseLcovReport, formatCoverageReport as formatCoverageAnalysis, formatStaticAnalysis, } from './coverage-analyzer.js'; +export type { CoverageMetrics, FileCoverage, UncoveredCode, CoverageAnalysis, StaticAnalysisIssue, StaticAnalysis, } from './coverage-analyzer.js'; diff --git a/dist/tools/index.js b/dist/tools/index.js index e2b5967..b0df90b 100644 --- a/dist/tools/index.js +++ b/dist/tools/index.js @@ -2,4 +2,9 @@ * Export all PR analysis tools */ export { parseDiff, createFileAnalyzerTool, createRiskDetectorTool, createComplexityScorerTool, createSummaryGeneratorTool, createCodeSuggestionTool, } from './pr-analysis-tools.js'; +export { detectTestFramework, isTestFile, isCodeFile, suggestTestFilePath, createTestSuggestionTool, generateTestTemplate, analyzeTestQuality, formatTestEnhancement, } from './test-suggestion-tool.js'; +export { detectCoverageTool, findCoverageFiles, readCoverageReport, createCoverageReporterTool, formatCoverageReport, } from './coverage-reporter.js'; +export { isDevOpsFile, analyzeDevOpsFiles, createDevOpsCostEstimatorTool, formatCostEstimates, } from './devops-cost-estimator.js'; +export { classifyProject, createProjectClassifierTool, formatClassification, } from './project-classifier.js'; +export { getCoverageAnalysis, runCoverageAnalysis, runEslintAnalysis, getLowCoverageFiles, detectCoverageReport, parseCoverageJson, parseLcovReport, formatCoverageReport as formatCoverageAnalysis, formatStaticAnalysis, } from './coverage-analyzer.js'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/tools/index.js.map b/dist/tools/index.js.map index fe58612..f93a79e 100644 --- a/dist/tools/index.js.map +++ b/dist/tools/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,wBAAwB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,eAAe,EACf,2BAA2B,EAC3B,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,IAAI,sBAAsB,EAC9C,oBAAoB,GACrB,MAAM,wBAAwB,CAAC"} \ No newline at end of file diff --git a/dist/tools/pr-analysis-tools.d.ts b/dist/tools/pr-analysis-tools.d.ts index 6a060da..309acf7 100644 --- a/dist/tools/pr-analysis-tools.d.ts +++ b/dist/tools/pr-analysis-tools.d.ts @@ -15,52 +15,76 @@ export declare function parseDiff(diff: string): DiffFile[]; export declare function createFileAnalyzerTool(): DynamicStructuredTool, { +}, "strip", z.ZodTypeAny, { filePath: string; diffContent: string; }, { filePath: string; diffContent: string; -}, string>; +}>, { + filePath: string; + diffContent: string; +}, { + filePath: string; + diffContent: string; +}, string, "analyze_file">; /** * Create risk detector tool */ export declare function createRiskDetectorTool(): DynamicStructuredTool; -}, z.core.$strip>, { +}, "strip", z.ZodTypeAny, { diff: string; context?: string | undefined; }, { diff: string; context?: string | undefined; -}, string>; +}>, { + diff: string; + context?: string | undefined; +}, { + diff: string; + context?: string | undefined; +}, string, "detect_risks">; /** * Create complexity scorer tool */ export declare function createComplexityScorerTool(): DynamicStructuredTool; + filesAnalyzed: z.ZodArray; totalChanges: z.ZodNumber; -}, z.core.$strip>, { +}, "strip", z.ZodTypeAny, { + filesAnalyzed: any[]; + totalChanges: number; +}, { + filesAnalyzed: any[]; + totalChanges: number; +}>, { filesAnalyzed: any[]; totalChanges: number; }, { filesAnalyzed: any[]; totalChanges: number; -}, string>; +}, string, "score_complexity">; /** * Create summary generator tool */ export declare function createSummaryGeneratorTool(): DynamicStructuredTool; + files: z.ZodArray; title: z.ZodOptional; -}, z.core.$strip>, { +}, "strip", z.ZodTypeAny, { files: any[]; title?: string | undefined; }, { files: any[]; title?: string | undefined; -}, string>; +}>, { + files: any[]; + title?: string | undefined; +}, { + files: any[]; + title?: string | undefined; +}, string, "generate_summary">; /** * Create code suggestion tool for fixing issues based on reviewer comments */ @@ -70,16 +94,28 @@ export declare function createCodeSuggestionTool(): DynamicStructuredTool; prContext: z.ZodOptional; -}, z.core.$strip>, { +}, "strip", z.ZodTypeAny, { + filePath: string; reviewerComment: string; codeSnippet: string; - filePath: string; prTitle?: string | undefined; prContext?: string | undefined; }, { + filePath: string; + reviewerComment: string; + codeSnippet: string; + prTitle?: string | undefined; + prContext?: string | undefined; +}>, { + filePath: string; reviewerComment: string; codeSnippet: string; + prTitle?: string | undefined; + prContext?: string | undefined; +}, { filePath: string; + reviewerComment: string; + codeSnippet: string; prTitle?: string | undefined; prContext?: string | undefined; -}, string>; +}, string, "suggest_code_fix">; diff --git a/dist/tools/project-classifier.d.ts b/dist/tools/project-classifier.d.ts new file mode 100644 index 0000000..24e0f95 --- /dev/null +++ b/dist/tools/project-classifier.d.ts @@ -0,0 +1,72 @@ +/** + * Project Classifier Tool + * + * Distinguishes between business logic and QA projects based on file patterns, + * content analysis, and project structure. This helps tailor analysis and + * recommendations to the project type. + * + * Business Logic Projects: + * - Focus on feature implementation, data models, APIs, business rules + * - Should prioritize: architecture review, performance, security + * + * QA/Test Projects: + * - Focus on testing, automation, test frameworks + * - Should prioritize: test coverage, test quality, maintainability + */ +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +export interface ProjectClassification { + projectType: 'business_logic' | 'qa_testing' | 'mixed' | 'unknown'; + confidence: number; + signals: { + businessLogicSignals: string[]; + qaTestingSignals: string[]; + }; + recommendations: string[]; +} +/** + * Classify a project based on changed files + */ +export declare function classifyProject(changedFiles: Array<{ + filename: string; + patch?: string; +}>): ProjectClassification; +/** + * Format classification results for display + */ +export declare function formatClassification(classification: ProjectClassification): string; +/** + * LangChain tool for project classification + */ +export declare function createProjectClassifierTool(): DynamicStructuredTool; + }, "strip", z.ZodTypeAny, { + filename: string; + patch?: string | undefined; + }, { + filename: string; + patch?: string | undefined; + }>, "many">; +}, "strip", z.ZodTypeAny, { + changedFiles: { + filename: string; + patch?: string | undefined; + }[]; +}, { + changedFiles: { + filename: string; + patch?: string | undefined; + }[]; +}>, { + changedFiles: { + filename: string; + patch?: string | undefined; + }[]; +}, { + changedFiles: { + filename: string; + patch?: string | undefined; + }[]; +}, string, "classify_project_type">; diff --git a/dist/tools/project-classifier.js b/dist/tools/project-classifier.js new file mode 100644 index 0000000..55b122e --- /dev/null +++ b/dist/tools/project-classifier.js @@ -0,0 +1,262 @@ +/** + * Project Classifier Tool + * + * Distinguishes between business logic and QA projects based on file patterns, + * content analysis, and project structure. This helps tailor analysis and + * recommendations to the project type. + * + * Business Logic Projects: + * - Focus on feature implementation, data models, APIs, business rules + * - Should prioritize: architecture review, performance, security + * + * QA/Test Projects: + * - Focus on testing, automation, test frameworks + * - Should prioritize: test coverage, test quality, maintainability + */ +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +/** + * Patterns that indicate business logic code + */ +const BUSINESS_LOGIC_PATTERNS = { + // File patterns + filePatterns: [ + /src\/.*\/(models?|entities|domain)\//i, + /src\/.*\/(services?|business|logic)\//i, + /src\/.*\/(controllers?|handlers?|routes?)\//i, + /src\/.*\/(api|graphql|rest)\//i, + /src\/.*\/(repositories?|dao|database)\//i, + /src\/.*\/(utils?|helpers?|lib)\//i, + /src\/.*\/(components?|views?|pages?)\//i, + ], + // Content patterns (in code) + contentKeywords: [ + 'class ', 'interface ', 'type ', 'enum ', + 'async ', 'await ', 'Promise', + 'export ', 'import ', + 'function', 'const', 'let', + 'router.', 'app.', 'express', + 'schema', 'model', 'entity', + 'query', 'mutation', 'resolver', + 'middleware', 'validation', + 'authentication', 'authorization', + ], +}; +/** + * Patterns that indicate QA/testing code + */ +const QA_TESTING_PATTERNS = { + // File patterns + filePatterns: [ + /test\//i, + /__tests__\//i, + /spec\//i, + /e2e\//i, + /integration\//i, + /\.test\./i, + /\.spec\./i, + /\.e2e\./i, + /cypress\//i, + /playwright\//i, + /selenium\//i, + ], + // Content patterns + contentKeywords: [ + 'describe(', 'it(', 'test(', + 'expect(', 'assert', 'should', + 'beforeEach', 'afterEach', 'beforeAll', 'afterAll', + 'jest.', 'vitest.', 'mocha', + 'cy.', 'page.', 'browser.', + 'fixture', 'mock', 'stub', 'spy', + 'snapshot', 'toMatchSnapshot', + 'toHaveBeenCalled', 'toEqual', 'toBe', + ], +}; +/** + * Classify a project based on changed files + */ +export function classifyProject(changedFiles) { + let businessLogicScore = 0; + let qaTestingScore = 0; + const businessLogicSignals = []; + const qaTestingSignals = []; + for (const file of changedFiles) { + const { filename, patch } = file; + // Check file patterns for business logic + for (const pattern of BUSINESS_LOGIC_PATTERNS.filePatterns) { + if (pattern.test(filename)) { + businessLogicScore += 1; + businessLogicSignals.push(`Business logic file: ${filename}`); + break; + } + } + // Check file patterns for QA/testing + for (const pattern of QA_TESTING_PATTERNS.filePatterns) { + if (pattern.test(filename)) { + qaTestingScore += 1; + qaTestingSignals.push(`Test file: ${filename}`); + break; + } + } + // Analyze patch content if available + if (patch) { + // Count business logic keywords + const businessKeywordCount = BUSINESS_LOGIC_PATTERNS.contentKeywords.filter(keyword => patch.includes(keyword)).length; + // Count QA/testing keywords + const qaKeywordCount = QA_TESTING_PATTERNS.contentKeywords.filter(keyword => patch.includes(keyword)).length; + if (businessKeywordCount > qaKeywordCount) { + businessLogicScore += businessKeywordCount * 0.1; + if (businessKeywordCount > 3) { + businessLogicSignals.push(`Business logic code patterns in ${filename}`); + } + } + else if (qaKeywordCount > businessKeywordCount) { + qaTestingScore += qaKeywordCount * 0.1; + if (qaKeywordCount > 3) { + qaTestingSignals.push(`Test code patterns in ${filename}`); + } + } + } + } + // Calculate total score and confidence + const totalScore = businessLogicScore + qaTestingScore; + const businessLogicRatio = totalScore > 0 ? businessLogicScore / totalScore : 0; + const qaTestingRatio = totalScore > 0 ? qaTestingScore / totalScore : 0; + // Determine project type based on ratios + let projectType; + let confidence; + if (totalScore === 0) { + projectType = 'unknown'; + confidence = 0; + } + else if (businessLogicRatio >= 0.8) { + projectType = 'business_logic'; + confidence = businessLogicRatio; + } + else if (qaTestingRatio >= 0.8) { + projectType = 'qa_testing'; + confidence = qaTestingRatio; + } + else { + projectType = 'mixed'; + confidence = 1 - Math.abs(businessLogicRatio - qaTestingRatio); + } + // Generate type-specific recommendations + const recommendations = generateRecommendations(projectType, { + businessLogicScore, + qaTestingScore, + changedFilesCount: changedFiles.length, + }); + return { + projectType, + confidence, + signals: { + businessLogicSignals, + qaTestingSignals, + }, + recommendations, + }; +} +/** + * Generate recommendations based on project type + */ +function generateRecommendations(projectType, context) { + const recommendations = []; + switch (projectType) { + case 'business_logic': + recommendations.push('📋 **Business Logic Project Detected** - Focus on architecture and data flow review', '🔒 Ensure proper input validation and error handling for business rules', '⚡ Consider performance implications for data processing and API endpoints', '🔐 Review authentication and authorization for sensitive business operations', '📊 Verify data model changes are properly migrated and validated'); + if (context.businessLogicScore > 10) { + recommendations.push('⚠️ Large business logic change - consider breaking into smaller PRs'); + } + break; + case 'qa_testing': + recommendations.push('🧪 **QA/Testing Project Detected** - Focus on test quality and coverage', '✅ Ensure tests are comprehensive and cover edge cases', '🎯 Verify test assertions are meaningful and specific', '♻️ Check for test maintainability and clear test descriptions', '🚀 Consider test execution time and potential for flakiness'); + if (context.qaTestingScore > 10) { + recommendations.push('📈 Extensive test changes - ensure all tests are passing and stable'); + } + break; + case 'mixed': + recommendations.push('🔀 **Mixed Project Type** - Changes span both business logic and tests', '🔄 Ensure business logic changes are properly covered by test changes', '⚖️ Verify test changes reflect the business logic modifications', '📝 Consider separating business logic and test changes into separate commits for clarity'); + break; + case 'unknown': + recommendations.push('❓ **Project Type Unknown** - Unable to determine primary focus', '🔍 Consider adding more context to file organization', '📚 Review if changes follow project structure conventions'); + break; + } + return recommendations; +} +/** + * Format classification results for display + */ +export function formatClassification(classification) { + const { projectType, confidence, signals, recommendations } = classification; + let output = `\n## 🏗️ Project Classification\n\n`; + // Project type badge + const typeEmoji = { + business_logic: '💼', + qa_testing: '🧪', + mixed: '🔀', + unknown: '❓', + }; + const typeName = { + business_logic: 'Business Logic', + qa_testing: 'QA/Testing', + mixed: 'Mixed', + unknown: 'Unknown', + }; + output += `**Type:** ${typeEmoji[projectType]} ${typeName[projectType]}\n`; + output += `**Confidence:** ${(confidence * 100).toFixed(0)}%\n\n`; + // Signals + if (signals.businessLogicSignals.length > 0 || signals.qaTestingSignals.length > 0) { + output += `### 🔍 Detection Signals\n\n`; + if (signals.businessLogicSignals.length > 0) { + output += `**Business Logic Indicators:**\n`; + signals.businessLogicSignals.slice(0, 5).forEach(signal => { + output += ` - ${signal}\n`; + }); + if (signals.businessLogicSignals.length > 5) { + output += ` - ...and ${signals.businessLogicSignals.length - 5} more\n`; + } + output += `\n`; + } + if (signals.qaTestingSignals.length > 0) { + output += `**QA/Testing Indicators:**\n`; + signals.qaTestingSignals.slice(0, 5).forEach(signal => { + output += ` - ${signal}\n`; + }); + if (signals.qaTestingSignals.length > 5) { + output += ` - ...and ${signals.qaTestingSignals.length - 5} more\n`; + } + output += `\n`; + } + } + // Recommendations + if (recommendations.length > 0) { + output += `### 💡 Type-Specific Recommendations\n\n`; + recommendations.forEach(rec => { + output += `${rec}\n\n`; + }); + } + return output; +} +/** + * LangChain tool for project classification + */ +export function createProjectClassifierTool() { + return new DynamicStructuredTool({ + name: 'classify_project_type', + description: 'Classifies the project type (business logic vs QA/testing) based on changed files. ' + + 'This helps tailor the PR review to focus on the most relevant aspects. ' + + 'Use this early in the analysis to understand the project context.', + schema: z.object({ + changedFiles: z.array(z.object({ + filename: z.string().describe('The file path'), + patch: z.string().optional().describe('The git diff patch content'), + })).describe('Array of changed files with their content'), + }), + func: async ({ changedFiles }) => { + const classification = classifyProject(changedFiles); + return formatClassification(classification); + }, + }); +} +//# sourceMappingURL=project-classifier.js.map \ No newline at end of file diff --git a/dist/tools/project-classifier.js.map b/dist/tools/project-classifier.js.map new file mode 100644 index 0000000..e296150 --- /dev/null +++ b/dist/tools/project-classifier.js.map @@ -0,0 +1 @@ +{"version":3,"file":"project-classifier.js","sourceRoot":"","sources":["../../src/tools/project-classifier.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/state-tools.d.ts b/dist/tools/state-tools.d.ts deleted file mode 100644 index cb40c5b..0000000 --- a/dist/tools/state-tools.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * State tools - get current state and remaining files - */ -import { DynamicStructuredTool } from '@langchain/core/tools'; -import type { ToolContext } from './types'; -export declare function createStateTools(context: ToolContext): DynamicStructuredTool[]; diff --git a/dist/tools/state-tools.js b/dist/tools/state-tools.js deleted file mode 100644 index 0c93ef8..0000000 --- a/dist/tools/state-tools.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -/** - * State tools - get current state and remaining files - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createStateTools = createStateTools; -const tools_1 = require("@langchain/core/tools"); -const zod_1 = require("zod"); -function createStateTools(context) { - const { state } = context; - const tools = []; - tools.push(new tools_1.DynamicStructuredTool({ - name: 'get_current_state', - description: 'Get the current analysis state: which files have been analyzed, which are pending, and current risks. Call this frequently to track progress. Shows exactly what still needs to be analyzed.', - schema: zod_1.z.object({}), - func: async () => { - const analyzedPaths = Array.from(state.analyzedFiles.keys()); - const pendingPaths = state.pendingFiles.map(f => ({ - path: f.path, - status: f.status || 'M', - additions: f.additions, - deletions: f.deletions, - totalChanges: f.additions + f.deletions - })); - const totalFiles = analyzedPaths.length + pendingPaths.length; - const progressPercent = totalFiles > 0 ? ((analyzedPaths.length / totalFiles) * 100).toFixed(1) : '0'; - return JSON.stringify({ - analyzed: analyzedPaths, - analyzedCount: analyzedPaths.length, - pending: pendingPaths, - pendingCount: pendingPaths.length, - totalFiles: totalFiles, - progressPercent: `${progressPercent}%`, - risksCount: state.risks.size, - insightsCount: state.insights.length, - message: pendingPaths.length === 0 - ? '✅ ALL FILES ANALYZED - Ready to synthesize' - : `⚠️ ${pendingPaths.length} files still need analysis: ${pendingPaths.map(p => p.path).join(', ')}` - }); - }, - })); - tools.push(new tools_1.DynamicStructuredTool({ - name: 'get_remaining_files', - description: 'Get a detailed list of all files that still need to be analyzed. Returns file paths with their status and change counts.', - schema: zod_1.z.object({}), - func: async () => { - const remaining = state.pendingFiles.map(f => ({ - path: f.path, - status: f.status || 'M', - additions: f.additions, - deletions: f.deletions, - totalChanges: f.additions + f.deletions, - priority: f.status === 'A' ? 'HIGH' : f.status === 'D' ? 'HIGH' : (f.additions + f.deletions) > 100 ? 'MEDIUM' : 'LOW' - })); - return JSON.stringify({ - remainingFiles: remaining, - count: remaining.length, - highPriority: remaining.filter(f => f.priority === 'HIGH').length, - mediumPriority: remaining.filter(f => f.priority === 'MEDIUM').length, - lowPriority: remaining.filter(f => f.priority === 'LOW').length - }); - }, - })); - return tools; -} -//# sourceMappingURL=state-tools.js.map \ No newline at end of file diff --git a/dist/tools/state-tools.js.map b/dist/tools/state-tools.js.map deleted file mode 100644 index 1bdabd2..0000000 --- a/dist/tools/state-tools.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"state-tools.js","sourceRoot":"","sources":["../../src/tools/state-tools.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/synthesize.d.ts b/dist/tools/synthesize.d.ts deleted file mode 100644 index f0565c3..0000000 --- a/dist/tools/synthesize.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Synthesize findings tool - synthesizes all analyzed files - */ -import { DynamicStructuredTool } from '@langchain/core/tools'; -import type { ToolContext } from './types'; -export declare function createSynthesizeTool(context: ToolContext): DynamicStructuredTool; diff --git a/dist/tools/synthesize.js b/dist/tools/synthesize.js deleted file mode 100644 index 0d76335..0000000 --- a/dist/tools/synthesize.js +++ /dev/null @@ -1,80 +0,0 @@ -"use strict"; -/** - * Synthesize findings tool - synthesizes all analyzed files - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createSynthesizeTool = createSynthesizeTool; -const tools_1 = require("@langchain/core/tools"); -const zod_1 = require("zod"); -const prompts_1 = require("../prompts"); -function createSynthesizeTool(context) { - const { state, provider } = context; - return new tools_1.DynamicStructuredTool({ - name: 'synthesize_findings', - description: 'Synthesize all analyzed files into overall insights. CRITICAL: Only call this when ALL files have been analyzed (get_current_state shows pendingCount = 0). Do not call this until every file is done.', - schema: zod_1.z.object({}), - func: async () => { - if (state.pendingFiles.length > 0) { - const remaining = state.pendingFiles.map(f => f.path).join(', '); - return JSON.stringify({ - error: `Cannot synthesize: ${state.pendingFiles.length} files still pending`, - pendingFiles: remaining, - message: `Please analyze these files first: ${remaining}` - }); - } - if (state.analyzedFiles.size === 0) { - return JSON.stringify({ - error: 'Cannot synthesize: No files have been analyzed yet', - message: 'Please analyze at least one file before synthesizing' - }); - } - const fileSummaries = Array.from(state.analyzedFiles.entries()) - .map(([path, analysis]) => `File: ${path}\n Summary: ${analysis.summary}\n Risks: ${analysis.risks.join(', ')}\n Complexity: ${analysis.complexity}/5`) - .join('\n\n'); - const synthesisContent = fileSummaries || 'No file summaries available'; - const outputFormat = state.outputFormat || 'terminal'; - const isTerminal = outputFormat === 'terminal'; - const synthesisPrompt = (0, prompts_1.buildSynthesisPrompt)(synthesisContent, state.context, state.analyzedFiles.size, isTerminal); - try { - const request = { - diff: synthesisContent, - title: 'Synthesizing PR analysis', - outputFormat: outputFormat - }; - const synthesis = await provider.analyze(request); - state.insights.push(synthesis.summary); - if (synthesis.recommendations) { - state.insights.push(...synthesis.recommendations); - } - state.lastSynthesis = synthesis; - return JSON.stringify({ - success: true, - ...synthesis, - message: 'Synthesis completed successfully' - }); - } - catch (error) { - const allRisks = Array.from(state.risks); - const avgComplexity = state.analyzedFiles.size > 0 - ? Math.round(Array.from(state.analyzedFiles.values()) - .reduce((sum, a) => sum + a.complexity, 0) / state.analyzedFiles.size) - : 3; - const fallbackSynthesis = { - summary: `Analyzed ${state.analyzedFiles.size} file(s). ${allRisks.length > 0 ? `Found ${allRisks.length} risk(s).` : 'No major risks identified.'}`, - risks: allRisks, - complexity: avgComplexity, - recommendations: state.insights.length > 0 ? state.insights.slice(0, 5) : [], - provider: provider.getProviderType(), - model: provider.config?.model || 'claude-sonnet-4-5-20250929' - }; - state.lastSynthesis = fallbackSynthesis; - return JSON.stringify({ - success: true, - ...fallbackSynthesis, - message: 'Synthesis completed (fallback)' - }); - } - }, - }); -} -//# sourceMappingURL=synthesize.js.map \ No newline at end of file diff --git a/dist/tools/synthesize.js.map b/dist/tools/synthesize.js.map deleted file mode 100644 index 9a14e5b..0000000 --- a/dist/tools/synthesize.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"synthesize.js","sourceRoot":"","sources":["../../src/tools/synthesize.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/test-suggestion-tool.d.ts b/dist/tools/test-suggestion-tool.d.ts new file mode 100644 index 0000000..f2cb13e --- /dev/null +++ b/dist/tools/test-suggestion-tool.d.ts @@ -0,0 +1,107 @@ +/** + * Test Suggestion Tool for PR Analysis + * Generates test code suggestions for code changes without corresponding tests + */ +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +/** + * Detect test framework from project configuration + */ +export declare function detectTestFramework(repoPath?: string): { + framework: 'jest' | 'mocha' | 'vitest' | 'pytest' | 'unittest' | 'other'; + detected: boolean; + configFile?: string; +}; +/** + * Check if a file is a test file + */ +export declare function isTestFile(filePath: string): boolean; +/** + * Check if a file is a code file that should have tests + */ +export declare function isCodeFile(filePath: string): boolean; +/** + * Generate test file path suggestion + */ +export declare function suggestTestFilePath(sourceFilePath: string, framework: string): string; +/** + * Create test suggestion tool + */ +export declare function createTestSuggestionTool(): DynamicStructuredTool, "many">; + framework: z.ZodOptional; + repoPath: z.ZodOptional; +}, "strip", z.ZodTypeAny, { + files: { + path: string; + diff: string; + additions: number; + }[]; + repoPath?: string | undefined; + framework?: string | undefined; +}, { + files: { + path: string; + diff: string; + additions: number; + }[]; + repoPath?: string | undefined; + framework?: string | undefined; +}>, { + files: { + path: string; + diff: string; + additions: number; + }[]; + repoPath?: string | undefined; + framework?: string | undefined; +}, { + files: { + path: string; + diff: string; + additions: number; + }[]; + repoPath?: string | undefined; + framework?: string | undefined; +}, string, "suggest_tests">; +/** + * Generate test code template based on framework and code + */ +export declare function generateTestTemplate(framework: string, filePath: string, codeSnippet: string, functionNames?: string[]): string; +/** + * Test Enhancement Suggestion - analyzes existing tests and suggests improvements + */ +export interface TestEnhancement { + testFile: string; + sourceFile: string; + currentTests: string[]; + missingScenarios: string[]; + suggestions: string[]; + enhancementCode?: string; +} +/** + * Analyze existing test file and suggest enhancements + */ +export declare function analyzeTestQuality(testFile: { + path: string; + diff: string; +}, sourceFile: { + path: string; + diff: string; +}, framework: string): TestEnhancement; +/** + * Format test enhancement for display + */ +export declare function formatTestEnhancement(enhancement: TestEnhancement): string; diff --git a/dist/tools/test-suggestion-tool.js b/dist/tools/test-suggestion-tool.js new file mode 100644 index 0000000..f50220b --- /dev/null +++ b/dist/tools/test-suggestion-tool.js @@ -0,0 +1,490 @@ +/** + * Test Suggestion Tool for PR Analysis + * Generates test code suggestions for code changes without corresponding tests + */ +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +import fs from 'node:fs'; +import path from 'node:path'; +/** + * Detect test framework from project configuration + */ +export function detectTestFramework(repoPath = '.') { + const packageJsonPath = path.join(repoPath, 'package.json'); + // Check for Node.js project + if (fs.existsSync(packageJsonPath)) { + try { + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); + const deps = { + ...packageJson.dependencies, + ...packageJson.devDependencies, + }; + // Check for Jest + if (deps.jest || deps['@jest/core'] || fs.existsSync(path.join(repoPath, 'jest.config.js')) || fs.existsSync(path.join(repoPath, 'jest.config.ts'))) { + return { framework: 'jest', detected: true, configFile: 'jest.config.js' }; + } + // Check for Vitest + if (deps.vitest || fs.existsSync(path.join(repoPath, 'vitest.config.js')) || fs.existsSync(path.join(repoPath, 'vitest.config.ts'))) { + return { framework: 'vitest', detected: true, configFile: 'vitest.config.js' }; + } + // Check for Mocha + if (deps.mocha || fs.existsSync(path.join(repoPath, '.mocharc.js')) || fs.existsSync(path.join(repoPath, '.mocharc.json'))) { + return { framework: 'mocha', detected: true, configFile: '.mocharc.js' }; + } + } + catch (e) { + // Ignore JSON parse errors + } + } + // Check for Python project + const pytestIni = path.join(repoPath, 'pytest.ini'); + const pyprojectToml = path.join(repoPath, 'pyproject.toml'); + const setupPy = path.join(repoPath, 'setup.py'); + if (fs.existsSync(pytestIni)) { + return { framework: 'pytest', detected: true, configFile: 'pytest.ini' }; + } + if (fs.existsSync(pyprojectToml)) { + try { + const content = fs.readFileSync(pyprojectToml, 'utf-8'); + if (content.includes('[tool.pytest]') || content.includes('pytest')) { + return { framework: 'pytest', detected: true, configFile: 'pyproject.toml' }; + } + } + catch (e) { + // Ignore read errors + } + } + if (fs.existsSync(setupPy)) { + try { + const content = fs.readFileSync(setupPy, 'utf-8'); + if (content.includes('pytest')) { + return { framework: 'pytest', detected: true, configFile: 'setup.py' }; + } + } + catch (e) { + // Ignore read errors + } + } + return { framework: 'other', detected: false }; +} +/** + * Check if a file is a test file + */ +export function isTestFile(filePath) { + const testPatterns = [ + /\.test\.[jt]sx?$/, + /\.spec\.[jt]sx?$/, + /_test\.py$/, + /test_.*\.py$/, + /\.test\.go$/, + /_test\.go$/, + /Test\.java$/, + /\.test\.rs$/, + ]; + return testPatterns.some(pattern => pattern.test(filePath)); +} +/** + * Check if a file is a code file that should have tests + */ +export function isCodeFile(filePath) { + const codeExtensions = ['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.java', '.rs', '.rb', '.cs']; + const ext = path.extname(filePath).toLowerCase(); + // Exclude config files, type definitions, etc. + if (filePath.includes('.d.ts') || filePath.includes('.config.') || filePath.includes('index.')) { + return false; + } + return codeExtensions.includes(ext); +} +/** + * Generate test file path suggestion + */ +export function suggestTestFilePath(sourceFilePath, framework) { + const ext = path.extname(sourceFilePath); + const baseName = path.basename(sourceFilePath, ext); + const dirName = path.dirname(sourceFilePath); + // For TypeScript/JavaScript + if (['.ts', '.tsx', '.js', '.jsx'].includes(ext)) { + if (framework === 'jest' || framework === 'vitest') { + // Check if there's a __tests__ folder pattern + if (dirName.includes('src')) { + const testsDir = dirName.replace('src', 'tests'); + return path.join(testsDir, `${baseName}.test${ext}`); + } + return path.join(dirName, `${baseName}.test${ext}`); + } + if (framework === 'mocha') { + return path.join(dirName, `${baseName}.spec${ext}`); + } + } + // For Python + if (ext === '.py') { + return path.join(dirName, `test_${baseName}.py`); + } + // For Go + if (ext === '.go') { + return path.join(dirName, `${baseName}_test.go`); + } + // Default + return path.join(dirName, `${baseName}.test${ext}`); +} +/** + * Create test suggestion tool + */ +export function createTestSuggestionTool() { + return new DynamicStructuredTool({ + name: 'suggest_tests', + description: 'Analyze code changes and suggest tests for files without test coverage', + schema: z.object({ + files: z.array(z.object({ + path: z.string(), + diff: z.string(), + additions: z.number(), + })).describe('Array of changed files to analyze'), + framework: z.string().optional().describe('Test framework to use'), + repoPath: z.string().optional().describe('Repository path for framework detection'), + }), + func: async ({ files, framework: providedFramework, repoPath }) => { + const detectedFramework = detectTestFramework(repoPath || '.'); + const testFramework = providedFramework || detectedFramework.framework; + // Filter to code files only + const codeFiles = files.filter(f => isCodeFile(f.path) && !isTestFile(f.path)); + // Check if corresponding test files exist in the PR + const testFilesInPR = files.filter(f => isTestFile(f.path)).map(f => f.path); + const filesNeedingTests = []; + for (const file of codeFiles) { + // Check if a test for this file is included in the PR + const baseNameWithoutExt = path.basename(file.path, path.extname(file.path)); + const hasPRTest = testFilesInPR.some(testPath => testPath.toLowerCase().includes(baseNameWithoutExt.toLowerCase())); + if (!hasPRTest && file.additions > 5) { // Only suggest for files with significant changes + // Extract added code from diff + const addedLines = file.diff + .split('\n') + .filter(line => line.startsWith('+') && !line.startsWith('+++')) + .map(line => line.substring(1)) + .join('\n'); + filesNeedingTests.push({ + file: file.path, + hasPRTest: false, + suggestedTestPath: suggestTestFilePath(file.path, testFramework), + codeSnippet: addedLines.substring(0, 1000), // Limit for context + }); + } + } + return JSON.stringify({ + testFramework, + frameworkDetected: detectedFramework.detected, + configFile: detectedFramework.configFile, + filesAnalyzed: codeFiles.length, + filesNeedingTests: filesNeedingTests.length, + files: filesNeedingTests, + }); + }, + }); +} +/** + * Generate test code template based on framework and code + */ +export function generateTestTemplate(framework, filePath, codeSnippet, functionNames = []) { + const baseName = path.basename(filePath, path.extname(filePath)); + const modulePath = filePath.replace(/\.[^/.]+$/, ''); + switch (framework) { + case 'jest': + case 'vitest': + return `import { describe, it, expect } from '${framework === 'vitest' ? 'vitest' : '@jest/globals'}'; +import { /* exported functions */ } from '${modulePath}'; + +describe('${baseName}', () => { +${functionNames.map(fn => ` describe('${fn}', () => { + it('should work correctly', () => { + // TODO: Add test implementation + expect(true).toBe(true); + }); + + it('should handle edge cases', () => { + // TODO: Add edge case tests + }); + }); +`).join('\n') || ` it('should be implemented', () => { + // TODO: Add tests for ${baseName} + expect(true).toBe(true); + }); +`} +}); +`; + case 'mocha': + return `const { expect } = require('chai'); +const { /* exported functions */ } = require('${modulePath}'); + +describe('${baseName}', function() { +${functionNames.map(fn => ` describe('${fn}', function() { + it('should work correctly', function() { + // TODO: Add test implementation + expect(true).to.be.true; + }); + }); +`).join('\n') || ` it('should be implemented', function() { + // TODO: Add tests for ${baseName} + expect(true).to.be.true; + }); +`} +}); +`; + case 'pytest': + return `import pytest +from ${modulePath.replace(/\//g, '.')} import * + +class Test${baseName.charAt(0).toUpperCase() + baseName.slice(1)}: +${functionNames.map(fn => ` def test_${fn}_works(self): + """Test that ${fn} works correctly.""" + # TODO: Add test implementation + assert True + + def test_${fn}_edge_cases(self): + """Test ${fn} edge cases.""" + # TODO: Add edge case tests + assert True +`).join('\n') || ` def test_implementation(self): + """Test ${baseName} functionality.""" + # TODO: Add tests + assert True +`} +`; + default: + return `// TODO: Add tests for ${baseName} +// Detected framework: ${framework} +// +// Test the following functionality: +${functionNames.map(fn => `// - ${fn}`).join('\n') || '// - Main module functionality'} +`; + } +} +/** + * Analyze existing test file and suggest enhancements + */ +export function analyzeTestQuality(testFile, sourceFile, framework) { + const testContent = testFile.diff; + const sourceContent = sourceFile.diff; + // Extract existing test cases from the test file + const currentTests = []; + const testPatterns = [ + /(?:test|it|describe)\s*\(\s*['"`]([^'"`]+)['"`]/g, // Jest/Mocha/Vitest + /def\s+test_(\w+)/g, // Python + ]; + for (const pattern of testPatterns) { + let match; + while ((match = pattern.exec(testContent)) !== null) { + currentTests.push(match[1]); + } + } + // Analyze source code to identify testable scenarios + const missingScenarios = []; + const suggestions = []; + // Check for common missing test scenarios + // 1. Error handling tests + if (sourceContent.includes('throw ') || sourceContent.includes('raise ') || + sourceContent.includes('Error(') || sourceContent.includes('Exception(')) { + const hasErrorTests = currentTests.some(t => /error|exception|throw|fail|invalid/i.test(t)); + if (!hasErrorTests) { + missingScenarios.push('Error handling tests'); + suggestions.push('⚠️ Add tests for error conditions and exception handling'); + } + } + // 2. Edge case tests + const hasEdgeCaseTests = currentTests.some(t => /edge|boundary|limit|empty|null|zero|max|min/i.test(t)); + if (!hasEdgeCaseTests && sourceContent.length > 100) { + missingScenarios.push('Edge case tests'); + suggestions.push('🔍 Add tests for edge cases (null, undefined, empty, boundary values)'); + } + // 3. Async operation tests + if ((sourceContent.includes('async ') || sourceContent.includes('await ') || + sourceContent.includes('Promise') || sourceContent.includes('.then(')) && + !testContent.includes('async ')) { + missingScenarios.push('Async operation tests'); + suggestions.push('⏱️ Add async/await tests for asynchronous operations'); + } + // 4. Input validation tests + if (sourceContent.includes('validate') || sourceContent.includes('check') || + sourceContent.match(/if\s*\(/)) { + const hasValidationTests = currentTests.some(t => /valid|invalid|check|verify/i.test(t)); + if (!hasValidationTests) { + missingScenarios.push('Input validation tests'); + suggestions.push('✅ Add tests for input validation and type checking'); + } + } + // 5. Return value tests + const hasReturnTests = currentTests.some(t => /return|result|output|expect/i.test(t)); + if (!hasReturnTests && (sourceContent.includes('return ') || sourceContent.includes('yield '))) { + missingScenarios.push('Return value verification'); + suggestions.push('🎯 Add explicit tests for expected return values and types'); + } + // 6. Side effects and state changes + if (sourceContent.match(/\.\w+\s*=/g) || sourceContent.includes('setState') || + sourceContent.includes('this.')) { + const hasStateTests = currentTests.some(t => /state|change|update|mutate/i.test(t)); + if (!hasStateTests) { + missingScenarios.push('State change tests'); + suggestions.push('🔄 Add tests to verify state changes and side effects'); + } + } + // 7. Integration/interaction tests + if (sourceContent.includes('import ') && currentTests.length < 3) { + suggestions.push('🔗 Consider adding integration tests for component interactions'); + } + // Generate enhancement code suggestions + let enhancementCode = ''; + if (missingScenarios.length > 0) { + enhancementCode = generateEnhancementCode(framework, testFile.path, missingScenarios); + } + return { + testFile: testFile.path, + sourceFile: sourceFile.path, + currentTests, + missingScenarios, + suggestions, + enhancementCode, + }; +} +/** + * Generate code for test enhancements + */ +function generateEnhancementCode(framework, testFilePath, missingScenarios) { + const baseName = path.basename(testFilePath, path.extname(testFilePath)); + switch (framework) { + case 'jest': + case 'vitest': + return ` +// === Suggested Test Enhancements === + +${missingScenarios.includes('Error handling tests') ? ` +describe('Error Handling', () => { + it('should handle invalid input gracefully', () => { + expect(() => functionName(null)).toThrow(); + expect(() => functionName(undefined)).toThrow(); + }); + + it('should throw appropriate error for edge cases', () => { + expect(() => functionName('')).toThrow('Invalid input'); + }); +}); +` : ''} + +${missingScenarios.includes('Edge case tests') ? ` +describe('Edge Cases', () => { + it('should handle empty input', () => { + expect(functionName('')).toBe(expectedEmptyResult); + }); + + it('should handle null and undefined', () => { + expect(functionName(null)).toBe(null); + expect(functionName(undefined)).toBe(undefined); + }); + + it('should handle boundary values', () => { + expect(functionName(0)).toBe(expectedZeroResult); + expect(functionName(Number.MAX_VALUE)).toBeDefined(); + }); +}); +` : ''} + +${missingScenarios.includes('Async operation tests') ? ` +describe('Async Operations', () => { + it('should resolve successfully', async () => { + const result = await asyncFunction(); + expect(result).toBeDefined(); + }); + + it('should handle async errors', async () => { + await expect(asyncFunction('invalid')).rejects.toThrow(); + }); +}); +` : ''} +`; + case 'mocha': + return ` +// === Suggested Test Enhancements === + +${missingScenarios.includes('Error handling tests') ? ` +describe('Error Handling', function() { + it('should handle invalid input gracefully', function() { + expect(() => functionName(null)).to.throw(); + }); +}); +` : ''} + +${missingScenarios.includes('Edge case tests') ? ` +describe('Edge Cases', function() { + it('should handle empty input', function() { + expect(functionName('')).to.equal(expectedEmptyResult); + }); + + it('should handle boundary values', function() { + expect(functionName(0)).to.be.defined; + }); +}); +` : ''} +`; + case 'pytest': + case 'unittest': + return ` +# === Suggested Test Enhancements === + +${missingScenarios.includes('Error handling tests') ? ` +def test_error_handling(): + """Test error handling with invalid inputs.""" + with pytest.raises(ValueError): + function_name(None) + with pytest.raises(ValueError): + function_name('') +` : ''} + +${missingScenarios.includes('Edge case tests') ? ` +def test_edge_cases(): + """Test edge cases and boundary conditions.""" + assert function_name('') == expected_empty_result + assert function_name(0) == expected_zero_result + assert function_name(None) is None +` : ''} + +${missingScenarios.includes('Async operation tests') ? ` +@pytest.mark.asyncio +async def test_async_operations(): + """Test asynchronous operations.""" + result = await async_function() + assert result is not None +` : ''} +`; + default: + return `// Consider adding tests for: ${missingScenarios.join(', ')}`; + } +} +/** + * Format test enhancement for display + */ +export function formatTestEnhancement(enhancement) { + let output = `\n### 🔬 Test Enhancement: ${path.basename(enhancement.testFile)}\n\n`; + output += `**Source File:** ${enhancement.sourceFile}\n`; + output += `**Current Tests:** ${enhancement.currentTests.length} test case(s)\n\n`; + if (enhancement.currentTests.length > 0 && enhancement.currentTests.length <= 5) { + output += `**Existing Tests:**\n`; + enhancement.currentTests.forEach(test => { + output += ` ✓ ${test}\n`; + }); + output += `\n`; + } + if (enhancement.missingScenarios.length > 0) { + output += `**Missing Test Scenarios:**\n`; + enhancement.missingScenarios.forEach(scenario => { + output += ` ⚠️ ${scenario}\n`; + }); + output += `\n`; + } + if (enhancement.suggestions.length > 0) { + output += `**Recommendations:**\n`; + enhancement.suggestions.forEach(suggestion => { + output += ` ${suggestion}\n`; + }); + output += `\n`; + } + return output; +} +//# sourceMappingURL=test-suggestion-tool.js.map \ No newline at end of file diff --git a/dist/tools/test-suggestion-tool.js.map b/dist/tools/test-suggestion-tool.js.map new file mode 100644 index 0000000..f522419 --- /dev/null +++ b/dist/tools/test-suggestion-tool.js.map @@ -0,0 +1 @@ +{"version":3,"file":"test-suggestion-tool.js","sourceRoot":"","sources":["../../src/tools/test-suggestion-tool.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/tools/types.d.ts b/dist/tools/types.d.ts deleted file mode 100644 index cdcac11..0000000 --- a/dist/tools/types.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Tool context types - */ -import { ChatAnthropic } from '@langchain/anthropic'; -import type { DiffFile, AgentState } from '../pr-agent'; -import type { BaseAIProvider } from '../providers/base'; -export interface ToolContext { - state: AgentState; - llm: ChatAnthropic; - provider: BaseAIProvider; - githubApi?: any; - repository?: { - owner: string; - repo: string; - baseSha?: string; - headSha?: string; - }; - getFileContent: (filePath: string, ref?: string) => string | null; - getDeletedFileContent: (filePath: string, ref?: string) => string | null; - calculatePriorityScore: (file: DiffFile, state: AgentState) => number; -} diff --git a/dist/tools/types.js b/dist/tools/types.js deleted file mode 100644 index d1bf0c6..0000000 --- a/dist/tools/types.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; -/** - * Tool context types - */ -Object.defineProperty(exports, "__esModule", { value: true }); -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dist/tools/types.js.map b/dist/tools/types.js.map deleted file mode 100644 index bd09b69..0000000 --- a/dist/tools/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":";AAAA;;GAEG"} \ No newline at end of file diff --git a/dist/types.d.ts b/dist/types.d.ts index a0c746d..50ee2ce 100644 --- a/dist/types.d.ts +++ b/dist/types.d.ts @@ -1,4 +1,4 @@ -export type AIProviderType = 'anthropic' | 'openai' | 'google'; +export type AIProviderType = 'anthropic' | 'openai' | 'google' | 'zhipu'; export interface PRInfo { number: number; title: string; diff --git a/dist/types/agent.types.d.ts b/dist/types/agent.types.d.ts index f5f2d6e..f9a11d7 100644 --- a/dist/types/agent.types.d.ts +++ b/dist/types/agent.types.d.ts @@ -43,6 +43,42 @@ export interface AnalysisMode { risks: boolean; complexity: boolean; } +/** + * Execution mode for LLM-agnostic operation + */ +export declare enum ExecutionMode { + EXECUTE = "execute",// CLI: Execute prompts with API key + PROMPT_ONLY = "prompt_only" +} +/** + * Individual analysis prompt for PROMPT_ONLY mode + * Supports both main PR analysis and peer review prompts + */ +export interface AnalysisPrompt { + step: 'fileAnalysis' | 'riskDetection' | 'summaryGeneration' | 'selfRefinement' | 'ticketQuality' | 'acValidation' | 'peerReview'; + prompt: string; + context?: Record; + instructions: string; + schema?: any; + formatInstructions?: string; + inputs?: Record; +} +/** + * Result when in PROMPT_ONLY mode - returns prompts instead of executing them + * Also includes static analysis results that don't require an LLM + */ +export interface PromptOnlyResult { + mode: 'prompt_only'; + context: AgentContext; + prompts: AnalysisPrompt[]; + instructions: string; + staticAnalysis?: { + testSuggestions?: TestSuggestion[]; + devOpsCostEstimates?: DevOpsCostEstimate[]; + coverageReport?: CoverageReport; + projectClassification?: string; + }; +} export interface RiskItem { description: string; archDocsReference?: { @@ -51,6 +87,59 @@ export interface RiskItem { reason: string; }; } +/** + * Code suggestion for fixing issues found during review + */ +export interface CodeSuggestion { + filePath: string; + lineRange: { + start: number; + end: number; + }; + originalCode: string; + suggestedCode: string; + reason: string; +} +/** + * Test suggestion for code without tests + */ +export interface TestSuggestion { + forFile: string; + testFramework: 'jest' | 'mocha' | 'vitest' | 'pytest' | 'unittest' | 'other'; + testCode: string; + description: string; + testFilePath?: string; + isEnhancement?: boolean; + existingTestFile?: string; +} +/** + * DevOps cost estimate for infrastructure changes + */ +export interface DevOpsCostEstimate { + resource: string; + resourceType: string; + currentMonthlyCost?: number; + estimatedNewCost: number; + difference?: number; + confidence: 'high' | 'medium' | 'low'; + details?: string; +} +/** + * Test coverage report + */ +export interface CoverageReport { + available: boolean; + overallPercentage?: number; + lineCoverage?: number; + branchCoverage?: number; + fileBreakdown?: Array<{ + file: string; + lineCoverage: number; + branchCoverage?: number; + }>; + delta?: number; + coverageTool?: string; +} export interface FileAnalysis { path: string; summary: string; @@ -61,6 +150,7 @@ export interface FileAnalysis { deletions: number; }; recommendations: string[]; + suggestedChanges?: CodeSuggestion[]; } export interface Fix { file: string; @@ -81,6 +171,8 @@ export interface AgentResult { totalTokensUsed: number; executionTime: number; mode: AnalysisMode; + overallComplexity?: number; + overallRisks?: string[]; archDocsImpact?: { used: boolean; docsAvailable: number; @@ -95,7 +187,15 @@ export interface AgentResult { warningCount: number; criticalIssues: string[]; }; + testSuggestions?: TestSuggestion[]; + devOpsCostEstimates?: DevOpsCostEstimate[]; + coverageReport?: CoverageReport; + projectClassification?: string; } +/** + * Union type for agent results - either executed results or prompts to execute + */ +export type AgentResultOrPrompts = AgentResult | PromptOnlyResult; export type AgentAnalysisResult = AgentResult; export interface AgentMetadata { name: string; diff --git a/dist/types/agent.types.js b/dist/types/agent.types.js index 2434200..7a58b57 100644 --- a/dist/types/agent.types.js +++ b/dist/types/agent.types.js @@ -2,6 +2,14 @@ * Agent types and interfaces for PR Agent * Following architecture-doc-generator patterns */ +/** + * Execution mode for LLM-agnostic operation + */ +export var ExecutionMode; +(function (ExecutionMode) { + ExecutionMode["EXECUTE"] = "execute"; + ExecutionMode["PROMPT_ONLY"] = "prompt_only"; +})(ExecutionMode || (ExecutionMode = {})); export var AgentPriority; (function (AgentPriority) { AgentPriority["HIGH"] = "high"; diff --git a/dist/types/agent.types.js.map b/dist/types/agent.types.js.map index b68ecf1..c4fbbe1 100644 --- a/dist/types/agent.types.js.map +++ b/dist/types/agent.types.js.map @@ -1 +1 @@ -{"version":3,"file":"agent.types.js","sourceRoot":"","sources":["../../src/types/agent.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAwHH,MAAM,CAAN,IAAY,aAIX;AAJD,WAAY,aAAa;IACvB,8BAAa,CAAA;IACb,kCAAiB,CAAA;IACjB,4BAAW,CAAA;AACb,CAAC,EAJW,aAAa,KAAb,aAAa,QAIxB"} \ No newline at end of file +{"version":3,"file":"agent.types.js","sourceRoot":"","sources":["../../src/types/agent.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+CH;;GAEG;AACH,MAAM,CAAN,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,oCAAmB,CAAA;IACnB,4CAA2B,CAAA;AAC7B,CAAC,EAHW,aAAa,KAAb,aAAa,QAGxB;AAgLD,MAAM,CAAN,IAAY,aAIX;AAJD,WAAY,aAAa;IACvB,8BAAa,CAAA;IACb,kCAAiB,CAAA;IACjB,4BAAW,CAAA;AACb,CAAC,EAJW,aAAa,KAAb,aAAa,QAIxB"} \ No newline at end of file diff --git a/dist/types/issue-tracker.types.d.ts b/dist/types/issue-tracker.types.d.ts new file mode 100644 index 0000000..6f87aeb --- /dev/null +++ b/dist/types/issue-tracker.types.d.ts @@ -0,0 +1,138 @@ +/** + * Generic Issue Tracker Provider Interface + * + * This abstraction allows PR Agent to work with different issue tracking systems + * (Jira, Linear, Azure DevOps, GitHub Issues, etc.) through a unified interface. + * + * MVP: Jira implementation via Atlassian MCP + * Future: Linear, Azure DevOps, GitHub Issues, etc. + */ +/** + * Normalized ticket/issue representation across all providers + */ +export interface IssueTicket { + id: string; + key: string; + url: string; + title: string; + description: string; + type: IssueType; + status: string; + priority: IssuePriority; + assignee?: string; + reporter?: string; + labels: string[]; + components: string[]; + project?: string; + storyPoints?: number; + estimate?: string; + acceptanceCriteria?: string; + acceptanceCriteriaList?: string[]; + testScenarios?: string[]; + linkedTestCases?: string[]; + hasScreenshots: boolean; + hasDiagrams: boolean; + attachmentCount: number; + parentKey?: string; + epicKey?: string; + linkedIssues: LinkedIssue[]; + subtasks: SubtaskInfo[]; + createdAt: string; + updatedAt: string; + rawData?: Record; +} +export type IssueType = 'bug' | 'feature' | 'story' | 'task' | 'epic' | 'subtask' | 'improvement' | 'spike' | 'other'; +export type IssuePriority = 'critical' | 'high' | 'medium' | 'low' | 'none'; +export interface LinkedIssue { + key: string; + type: string; + title: string; + status: string; +} +export interface SubtaskInfo { + key: string; + title: string; + status: string; +} +/** + * Reference to a ticket found in PR metadata + */ +export interface TicketReference { + key: string; + source: 'title' | 'description' | 'branch' | 'commit' | 'manual'; + rawMatch: string; + confidence: number; +} +/** + * Issue tracker provider interface - implement this for each provider + */ +export interface IssueTrackerProvider { + /** + * Provider name for display and configuration + */ + readonly name: string; + /** + * Provider type identifier + */ + readonly type: IssueTrackerType; + /** + * Check if the provider is properly configured and accessible + */ + isConfigured(): boolean; + /** + * Test connection to the provider + */ + testConnection(): Promise; + /** + * Fetch a single ticket by key + */ + getTicket(key: string): Promise; + /** + * Fetch multiple tickets by keys + */ + getTickets(keys: string[]): Promise; + /** + * Extract ticket references from PR metadata + */ + extractTicketReferences(context: TicketExtractionContext): TicketReference[]; + /** + * Search for tickets matching a query + */ + searchTickets?(query: string, limit?: number): Promise; + /** + * Get ticket comments (if supported) + */ + getComments?(ticketKey: string): Promise; +} +export type IssueTrackerType = 'jira' | 'linear' | 'azure-devops' | 'github-issues' | 'gitlab-issues' | 'shortcut' | 'asana' | 'other'; +export interface TicketExtractionContext { + prTitle: string; + prDescription?: string; + branchName?: string; + commitMessages?: string[]; +} +export interface IssueComment { + id: string; + author: string; + body: string; + createdAt: string; +} +/** + * Configuration for issue tracker integration + */ +export interface IssueTrackerConfig { + enabled: boolean; + provider: IssueTrackerType; + providerConfig: Record; + analyzeAcceptanceCriteria: boolean; + rateTicketQuality: boolean; + generateTestSuggestions: boolean; + checkScopeCreep: boolean; + ticketPatterns?: string[]; + includeTicketDetails: boolean; + verbose: boolean; +} +/** + * Factory function type for creating providers + */ +export type IssueTrackerProviderFactory = (config: IssueTrackerConfig) => IssueTrackerProvider | null; diff --git a/dist/types/issue-tracker.types.js b/dist/types/issue-tracker.types.js new file mode 100644 index 0000000..5e61f2a --- /dev/null +++ b/dist/types/issue-tracker.types.js @@ -0,0 +1,11 @@ +/** + * Generic Issue Tracker Provider Interface + * + * This abstraction allows PR Agent to work with different issue tracking systems + * (Jira, Linear, Azure DevOps, GitHub Issues, etc.) through a unified interface. + * + * MVP: Jira implementation via Atlassian MCP + * Future: Linear, Azure DevOps, GitHub Issues, etc. + */ +export {}; +//# sourceMappingURL=issue-tracker.types.js.map \ No newline at end of file diff --git a/dist/types/issue-tracker.types.js.map b/dist/types/issue-tracker.types.js.map new file mode 100644 index 0000000..51d6878 --- /dev/null +++ b/dist/types/issue-tracker.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"issue-tracker.types.js","sourceRoot":"","sources":["../../src/types/issue-tracker.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"} \ No newline at end of file diff --git a/dist/types/jira.types.d.ts b/dist/types/jira.types.d.ts new file mode 100644 index 0000000..356236e --- /dev/null +++ b/dist/types/jira.types.d.ts @@ -0,0 +1,211 @@ +/** + * Jira types and interfaces for Peer Review Agent + * Provides structures for Jira ticket analysis and acceptance criteria validation + */ +/** + * Jira ticket from the Atlassian API/MCP + */ +export interface JiraTicket { + key: string; + id: string; + summary: string; + description: string; + status: string; + type: JiraTicketType; + priority: string; + assignee?: string; + reporter?: string; + labels: string[]; + components: string[]; + fixVersions: string[]; + storyPoints?: number; + createdAt: string; + updatedAt: string; + acceptanceCriteria?: string; + acceptanceCriteriaItems?: AcceptanceCriteriaItem[]; + testScenarios?: string[]; + testCases?: string[]; + attachments?: JiraAttachment[]; + linkedIssues?: JiraLinkedIssue[]; + comments?: JiraComment[]; + subtasks?: JiraSubtask[]; + parentKey?: string; + epicKey?: string; + customFields?: Record; +} +export type JiraTicketType = 'bug' | 'feature' | 'task' | 'story' | 'epic' | 'subtask' | 'improvement' | 'other'; +export interface AcceptanceCriteriaItem { + id: string; + text: string; + isMet?: boolean; + coverageDetails?: string; + relatedFiles?: string[]; + confidence: number; +} +export interface JiraAttachment { + id: string; + filename: string; + mimeType: string; + url: string; + createdAt: string; + isScreenshot: boolean; +} +export interface JiraLinkedIssue { + key: string; + type: string; + summary: string; + status: string; +} +export interface JiraComment { + id: string; + author: string; + body: string; + createdAt: string; +} +export interface JiraSubtask { + key: string; + summary: string; + status: string; +} +/** + * Ticket quality rating based on best practices + */ +export interface TicketQualityRating { + overallScore: number; + dimensions: { + descriptionClarity: number; + acceptanceCriteriaQuality: number; + testabilityScore: number; + scopeDefinition: number; + technicalContext: number; + visualDocumentation: number; + estimationQuality: number; + completeness: number; + }; + feedback: { + strengths: string[]; + weaknesses: string[]; + suggestions: string[]; + }; + tier: 'excellent' | 'good' | 'adequate' | 'poor' | 'insufficient'; + reviewable: boolean; + reviewabilityReason: string; +} +/** + * Result of acceptance criteria validation against PR changes + */ +export interface AcceptanceCriteriaValidation { + ticketKey: string; + totalCriteria: number; + metCriteria: number; + unmetCriteria: number; + partialCriteria: number; + criteriaAnalysis: CriteriaAnalysisItem[]; + compliancePercentage: number; + gaps: AcceptanceCriteriaGap[]; + suggestedTestScenarios: TestScenarioSuggestion[]; +} +export interface CriteriaAnalysisItem { + criteriaId: string; + criteriaText: string; + status: 'met' | 'unmet' | 'partial' | 'unclear'; + confidence: number; + evidence: string[]; + explanation: string; + relatedFiles: string[]; +} +export interface AcceptanceCriteriaGap { + criteriaText: string; + gapDescription: string; + severity: 'critical' | 'major' | 'minor'; + suggestedAction: string; +} +export interface TestScenarioSuggestion { + scenario: string; + type: 'unit' | 'integration' | 'e2e' | 'manual'; + priority: 'high' | 'medium' | 'low'; + relatedCriteria: string[]; + suggestedApproach: string; +} +/** + * Complete Jira analysis result for a PR + */ +export interface JiraAnalysisResult { + linkedTickets: JiraTicket[]; + primaryTicket?: JiraTicket; + ticketQuality?: TicketQualityRating; + acValidation?: AcceptanceCriteriaValidation; + scopeAnalysis: { + inScope: string[]; + outOfScope: string[]; + scopeCreepRisk: boolean; + scopeCreepDetails?: string; + }; + edgeCaseAnalysis: { + identifiedEdgeCases: string[]; + coveredEdgeCases: string[]; + uncoveredEdgeCases: string[]; + testSuggestions: TestScenarioSuggestion[]; + }; + overallAssessment: { + implementationCompleteness: number; + qualityScore: number; + readyForReview: boolean; + blockers: string[]; + warnings: string[]; + recommendations: string[]; + }; + metrics: { + ticketsCovered: number; + criteriaTotal: number; + criteriaMet: number; + criteriaPartial: number; + criteriaUnmet: number; + testScenariosGenerated: number; + }; +} +/** + * Configuration for Jira integration + */ +export interface JiraConfig { + enabled: boolean; + mcpServerUrl?: string; + instanceUrl?: string; + projectKey?: string; + apiToken?: string; + email?: string; + analyzeAcceptanceCriteria: boolean; + rateTicketQuality: boolean; + generateTestSuggestions: boolean; + checkScopeCreep: boolean; + includeTicketDetailsInOutput: boolean; + verboseOutput: boolean; +} +/** + * Ticket reference extracted from PR title/description/branch + */ +export interface TicketReference { + key: string; + source: 'title' | 'description' | 'branch' | 'commit'; + confidence: number; +} +/** + * Context passed to Jira sub-agent + */ +export interface JiraAnalysisContext { + prTitle: string; + prDescription?: string; + branchName?: string; + commitMessages?: string[]; + diff: string; + files: Array<{ + path: string; + additions: number; + deletions: number; + status: string; + }>; + prSummary?: string; + prRisks?: string[]; + prComplexity?: number; + config: JiraConfig; +} diff --git a/dist/types/jira.types.js b/dist/types/jira.types.js new file mode 100644 index 0000000..edce57c --- /dev/null +++ b/dist/types/jira.types.js @@ -0,0 +1,6 @@ +/** + * Jira types and interfaces for Peer Review Agent + * Provides structures for Jira ticket analysis and acceptance criteria validation + */ +export {}; +//# sourceMappingURL=jira.types.js.map \ No newline at end of file diff --git a/dist/types/jira.types.js.map b/dist/types/jira.types.js.map new file mode 100644 index 0000000..961155b --- /dev/null +++ b/dist/types/jira.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"jira.types.js","sourceRoot":"","sources":["../../src/types/jira.types.ts"],"names":[],"mappings":"AAAA;;;GAGG"} \ No newline at end of file diff --git a/dist/utils/config-validator.d.ts b/dist/utils/config-validator.d.ts index 2b52001..124a0cf 100644 --- a/dist/utils/config-validator.d.ts +++ b/dist/utils/config-validator.d.ts @@ -11,42 +11,238 @@ export declare const UserConfigSchema: z.ZodObject<{ anthropic: z.ZodOptional; openai: z.ZodOptional; google: z.ZodOptional; - }, z.core.$strip>>; + zhipu: z.ZodOptional; + }, "strip", z.ZodTypeAny, { + anthropic?: string | undefined; + openai?: string | undefined; + google?: string | undefined; + zhipu?: string | undefined; + }, { + anthropic?: string | undefined; + openai?: string | undefined; + google?: string | undefined; + zhipu?: string | undefined; + }>>; ai: z.ZodOptional>; + provider: z.ZodOptional>; model: z.ZodOptional; temperature: z.ZodOptional; maxTokens: z.ZodOptional; - }, z.core.$strip>>; + }, "strip", z.ZodTypeAny, { + provider?: "anthropic" | "openai" | "google" | "zhipu" | undefined; + model?: string | undefined; + temperature?: number | undefined; + maxTokens?: number | undefined; + }, { + provider?: "anthropic" | "openai" | "google" | "zhipu" | undefined; + model?: string | undefined; + temperature?: number | undefined; + maxTokens?: number | undefined; + }>>; analysis: z.ZodOptional>; + defaultMode: z.ZodOptional>; maxCost: z.ZodOptional; autoDetectAgent: z.ZodOptional; agentThreshold: z.ZodOptional; language: z.ZodOptional; framework: z.ZodOptional; enableStaticAnalysis: z.ZodOptional; - }, z.core.$strip>>; + }, "strip", z.ZodTypeAny, { + language?: string | undefined; + framework?: string | undefined; + defaultMode?: "summary" | "complexity" | "risks" | "full" | undefined; + autoDetectAgent?: boolean | undefined; + enableStaticAnalysis?: boolean | undefined; + maxCost?: number | undefined; + agentThreshold?: number | undefined; + }, { + language?: string | undefined; + framework?: string | undefined; + defaultMode?: "summary" | "complexity" | "risks" | "full" | undefined; + autoDetectAgent?: boolean | undefined; + enableStaticAnalysis?: boolean | undefined; + maxCost?: number | undefined; + agentThreshold?: number | undefined; + }>>; git: z.ZodOptional; + defaultBranch: z.ZodOptional>; includeUntracked: z.ZodOptional; - excludePatterns: z.ZodOptional>; - }, z.core.$strip>>; + excludePatterns: z.ZodOptional>; + }, "strip", z.ZodTypeAny, { + defaultBranch?: string | undefined; + includeUntracked?: boolean | undefined; + excludePatterns?: string[] | undefined; + }, { + defaultBranch?: string | undefined; + includeUntracked?: boolean | undefined; + excludePatterns?: string[] | undefined; + }>>; output: z.ZodOptional; showStrategy: z.ZodOptional; showRecommendations: z.ZodOptional; - }, z.core.$strip>>; -}, z.core.$strip>; + }, "strip", z.ZodTypeAny, { + verbose?: boolean | undefined; + showStrategy?: boolean | undefined; + showRecommendations?: boolean | undefined; + }, { + verbose?: boolean | undefined; + showStrategy?: boolean | undefined; + showRecommendations?: boolean | undefined; + }>>; + peerReview: z.ZodOptional; + provider: z.ZodOptional; + useMcp: z.ZodOptional; + instanceUrl: z.ZodOptional; + email: z.ZodOptional; + apiToken: z.ZodOptional; + defaultProject: z.ZodOptional; + acceptanceCriteriaField: z.ZodOptional; + storyPointsField: z.ZodOptional; + ticketPatterns: z.ZodOptional>; + analyzeAcceptanceCriteria: z.ZodOptional; + rateTicketQuality: z.ZodOptional; + generateTestSuggestions: z.ZodOptional; + checkScopeCreep: z.ZodOptional; + includeTicketDetails: z.ZodOptional; + verbose: z.ZodOptional; + }, "strip", z.ZodTypeAny, { + provider?: string | undefined; + email?: string | undefined; + enabled?: boolean | undefined; + useMcp?: boolean | undefined; + instanceUrl?: string | undefined; + apiToken?: string | undefined; + defaultProject?: string | undefined; + acceptanceCriteriaField?: string | undefined; + storyPointsField?: string | undefined; + ticketPatterns?: string[] | undefined; + verbose?: boolean | undefined; + analyzeAcceptanceCriteria?: boolean | undefined; + rateTicketQuality?: boolean | undefined; + generateTestSuggestions?: boolean | undefined; + checkScopeCreep?: boolean | undefined; + includeTicketDetails?: boolean | undefined; + }, { + provider?: string | undefined; + email?: string | undefined; + enabled?: boolean | undefined; + useMcp?: boolean | undefined; + instanceUrl?: string | undefined; + apiToken?: string | undefined; + defaultProject?: string | undefined; + acceptanceCriteriaField?: string | undefined; + storyPointsField?: string | undefined; + ticketPatterns?: string[] | undefined; + verbose?: boolean | undefined; + analyzeAcceptanceCriteria?: boolean | undefined; + rateTicketQuality?: boolean | undefined; + generateTestSuggestions?: boolean | undefined; + checkScopeCreep?: boolean | undefined; + includeTicketDetails?: boolean | undefined; + }>>; +}, "strip", z.ZodTypeAny, { + ai?: { + provider?: "anthropic" | "openai" | "google" | "zhipu" | undefined; + model?: string | undefined; + temperature?: number | undefined; + maxTokens?: number | undefined; + } | undefined; + peerReview?: { + provider?: string | undefined; + email?: string | undefined; + enabled?: boolean | undefined; + useMcp?: boolean | undefined; + instanceUrl?: string | undefined; + apiToken?: string | undefined; + defaultProject?: string | undefined; + acceptanceCriteriaField?: string | undefined; + storyPointsField?: string | undefined; + ticketPatterns?: string[] | undefined; + verbose?: boolean | undefined; + analyzeAcceptanceCriteria?: boolean | undefined; + rateTicketQuality?: boolean | undefined; + generateTestSuggestions?: boolean | undefined; + checkScopeCreep?: boolean | undefined; + includeTicketDetails?: boolean | undefined; + } | undefined; + output?: { + verbose?: boolean | undefined; + showStrategy?: boolean | undefined; + showRecommendations?: boolean | undefined; + } | undefined; + analysis?: { + language?: string | undefined; + framework?: string | undefined; + defaultMode?: "summary" | "complexity" | "risks" | "full" | undefined; + autoDetectAgent?: boolean | undefined; + enableStaticAnalysis?: boolean | undefined; + maxCost?: number | undefined; + agentThreshold?: number | undefined; + } | undefined; + git?: { + defaultBranch?: string | undefined; + includeUntracked?: boolean | undefined; + excludePatterns?: string[] | undefined; + } | undefined; + apiKeys?: { + anthropic?: string | undefined; + openai?: string | undefined; + google?: string | undefined; + zhipu?: string | undefined; + } | undefined; +}, { + ai?: { + provider?: "anthropic" | "openai" | "google" | "zhipu" | undefined; + model?: string | undefined; + temperature?: number | undefined; + maxTokens?: number | undefined; + } | undefined; + peerReview?: { + provider?: string | undefined; + email?: string | undefined; + enabled?: boolean | undefined; + useMcp?: boolean | undefined; + instanceUrl?: string | undefined; + apiToken?: string | undefined; + defaultProject?: string | undefined; + acceptanceCriteriaField?: string | undefined; + storyPointsField?: string | undefined; + ticketPatterns?: string[] | undefined; + verbose?: boolean | undefined; + analyzeAcceptanceCriteria?: boolean | undefined; + rateTicketQuality?: boolean | undefined; + generateTestSuggestions?: boolean | undefined; + checkScopeCreep?: boolean | undefined; + includeTicketDetails?: boolean | undefined; + } | undefined; + output?: { + verbose?: boolean | undefined; + showStrategy?: boolean | undefined; + showRecommendations?: boolean | undefined; + } | undefined; + analysis?: { + language?: string | undefined; + framework?: string | undefined; + defaultMode?: "summary" | "complexity" | "risks" | "full" | undefined; + autoDetectAgent?: boolean | undefined; + enableStaticAnalysis?: boolean | undefined; + maxCost?: number | undefined; + agentThreshold?: number | undefined; + } | undefined; + git?: { + defaultBranch?: string | undefined; + includeUntracked?: boolean | undefined; + excludePatterns?: string[] | undefined; + } | undefined; + apiKeys?: { + anthropic?: string | undefined; + openai?: string | undefined; + google?: string | undefined; + zhipu?: string | undefined; + } | undefined; +}>; /** * Validate configuration object */ diff --git a/dist/utils/config-validator.js b/dist/utils/config-validator.js index b4ac405..b2f2ef6 100644 --- a/dist/utils/config-validator.js +++ b/dist/utils/config-validator.js @@ -12,11 +12,12 @@ export const UserConfigSchema = z.object({ anthropic: z.string().optional(), openai: z.string().optional(), google: z.string().optional(), + zhipu: z.string().optional(), }) .optional(), ai: z .object({ - provider: z.enum(['anthropic', 'openai', 'google']).optional(), + provider: z.enum(['anthropic', 'openai', 'google', 'zhipu']).optional(), model: z.string().optional(), temperature: z.number().min(0).max(2).optional(), maxTokens: z.number().positive().int().optional(), @@ -62,6 +63,26 @@ export const UserConfigSchema = z.object({ showRecommendations: z.boolean().optional(), }) .optional(), + peerReview: z + .object({ + enabled: z.boolean().optional(), + provider: z.string().optional(), + useMcp: z.boolean().optional(), + instanceUrl: z.string().url().optional(), + email: z.string().email().optional(), + apiToken: z.string().optional(), + defaultProject: z.string().optional(), + acceptanceCriteriaField: z.string().optional(), + storyPointsField: z.string().optional(), + ticketPatterns: z.array(z.string()).optional(), + analyzeAcceptanceCriteria: z.boolean().optional(), + rateTicketQuality: z.boolean().optional(), + generateTestSuggestions: z.boolean().optional(), + checkScopeCreep: z.boolean().optional(), + includeTicketDetails: z.boolean().optional(), + verbose: z.boolean().optional(), + }) + .optional(), }); /** * Validate configuration object diff --git a/dist/utils/config-validator.js.map b/dist/utils/config-validator.js.map index 5322842..7698641 100644 --- a/dist/utils/config-validator.js.map +++ b/dist/utils/config-validator.js.map @@ -1 +1 @@ -{"version":3,"file":"config-validator.js","sourceRoot":"","sources":["../../src/utils/config-validator.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"config-validator.js","sourceRoot":"","sources":["../../src/utils/config-validator.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/utils/output-formatter.d.ts b/dist/utils/output-formatter.d.ts new file mode 100644 index 0000000..0404e51 --- /dev/null +++ b/dist/utils/output-formatter.d.ts @@ -0,0 +1,57 @@ +/** + * Shared output formatting for CLI and MCP server + * Supports both terminal (chalk colors) and markdown output modes + */ +export type OutputMode = 'terminal' | 'markdown'; +export interface FormatterOptions { + mode: OutputMode; + verbose?: boolean; +} +/** + * Output formatter that can generate terminal or markdown output + */ +export declare class OutputFormatter { + private mode; + private verbose; + constructor(options: FormatterOptions); + /** + * Format a section separator line + */ + separator(): string; + /** + * Format a bold title + */ + bold(text: string): string; + /** + * Format a colored title + */ + title(text: string, color?: 'green' | 'cyan' | 'yellow' | 'blue' | 'red'): string; + /** + * Format regular text + */ + text(text: string): string; + /** + * Format gray/dimmed text + */ + dim(text: string): string; + /** + * Format test suggestions section + */ + formatTestSuggestions(testSuggestions: any[]): string; + /** + * Format project classification section + */ + formatProjectClassification(classification: string | undefined): string; + /** + * Format coverage report section + */ + formatCoverageReport(coverageReport: any): string; + /** + * Format DevOps cost estimates section + */ + formatDevOpsCostEstimates(costEstimates: any[]): string; + /** + * Format static analysis section + */ + formatStaticAnalysis(staticAnalysis: any): string; +} diff --git a/dist/utils/output-formatter.js b/dist/utils/output-formatter.js new file mode 100644 index 0000000..2c802d6 --- /dev/null +++ b/dist/utils/output-formatter.js @@ -0,0 +1,319 @@ +/** + * Shared output formatting for CLI and MCP server + * Supports both terminal (chalk colors) and markdown output modes + */ +import chalk from 'chalk'; +/** + * Output formatter that can generate terminal or markdown output + */ +export class OutputFormatter { + mode; + verbose; + constructor(options) { + this.mode = options.mode; + this.verbose = options.verbose || false; + } + /** + * Format a section separator line + */ + separator() { + if (this.mode === 'markdown') { + return '\n---\n'; + } + return chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + } + /** + * Format a bold title + */ + bold(text) { + if (this.mode === 'markdown') { + return `**${text}**`; + } + return chalk.bold(text); + } + /** + * Format a colored title + */ + title(text, color = 'cyan') { + if (this.mode === 'markdown') { + return `## ${text}`; + } + const chalkColor = chalk[color].bold; + return chalkColor(text); + } + /** + * Format regular text + */ + text(text) { + if (this.mode === 'markdown') { + return text; + } + return chalk.white(text); + } + /** + * Format gray/dimmed text + */ + dim(text) { + if (this.mode === 'markdown') { + return text; + } + return chalk.gray(text); + } + /** + * Format test suggestions section + */ + formatTestSuggestions(testSuggestions) { + if (!testSuggestions || testSuggestions.length === 0) { + return ''; + } + const lines = []; + const newTests = testSuggestions.filter((s) => !s.isEnhancement); + const enhancements = testSuggestions.filter((s) => s.isEnhancement); + // New test suggestions + if (newTests.length > 0) { + lines.push(this.separator()); + lines.push(''); + if (this.mode === 'markdown') { + lines.push(`### 🧪 Test Suggestions (${newTests.length})`); + } + else { + lines.push(chalk.yellow.bold(`🧪 Test Suggestions (${newTests.length} files need tests)`)); + } + lines.push(''); + for (const suggestion of newTests) { + if (this.mode === 'markdown') { + lines.push(`**${suggestion.forFile}**`); + lines.push(`- Framework: ${suggestion.testFramework}`); + if (suggestion.testFilePath) { + lines.push(`- Suggested path: ${suggestion.testFilePath}`); + } + lines.push(''); + } + else { + lines.push(chalk.cyan(` 📝 ${suggestion.forFile}`)); + lines.push(chalk.gray(` Framework: ${suggestion.testFramework}`)); + if (suggestion.testFilePath) { + lines.push(chalk.gray(` Suggested test file: ${suggestion.testFilePath}`)); + } + lines.push(chalk.white(` ${suggestion.description}`)); + lines.push(''); + // Show test code preview for terminal + if (suggestion.testCode) { + lines.push(chalk.gray(' ┌─────────────────────────────────────────')); + const codeLines = suggestion.testCode.split('\n').slice(0, 10); + codeLines.forEach((line) => { + lines.push(chalk.gray(' │ ') + chalk.white(line)); + }); + if (suggestion.testCode.split('\n').length > 10) { + lines.push(chalk.gray(' │ ... (copy full code below)')); + } + lines.push(chalk.gray(' └─────────────────────────────────────────')); + lines.push(''); + } + } + } + } + // Test enhancement suggestions + if (enhancements.length > 0) { + lines.push(this.separator()); + lines.push(''); + if (this.mode === 'markdown') { + lines.push(`### 🔬 Test Enhancement Suggestions (${enhancements.length})`); + } + else { + lines.push(chalk.green.bold(`🔬 Test Enhancement Suggestions (${enhancements.length} test files can be improved)`)); + } + lines.push(''); + for (const suggestion of enhancements) { + const testFile = suggestion.existingTestFile || suggestion.testFilePath; + if (this.mode === 'markdown') { + lines.push(`**${testFile}**`); + lines.push(`- Source: ${suggestion.forFile}`); + lines.push(`- ${suggestion.description}`); + lines.push(''); + } + else { + lines.push(chalk.cyan(` 📊 ${testFile}`)); + lines.push(chalk.gray(` Source: ${suggestion.forFile}`)); + lines.push(chalk.white(` ${suggestion.description}`)); + lines.push(''); + // Show test code preview for terminal + if (suggestion.testCode && suggestion.testCode.trim()) { + lines.push(chalk.gray(' ┌─────────────────────────────────────────')); + const codeLines = suggestion.testCode.split('\n').slice(0, 15); + codeLines.forEach((line) => { + lines.push(chalk.gray(' │ ') + chalk.white(line)); + }); + if (suggestion.testCode.split('\n').length > 15) { + lines.push(chalk.gray(' │ ... (more enhancements available)')); + } + lines.push(chalk.gray(' └─────────────────────────────────────────')); + lines.push(''); + } + } + } + } + return lines.join('\n'); + } + /** + * Format project classification section + */ + formatProjectClassification(classification) { + if (!classification) { + return ''; + } + const lines = []; + lines.push(this.separator()); + if (this.mode === 'markdown') { + lines.push(''); + lines.push(classification); + } + else { + // Classification already has chalk formatting from the agent + lines.push(classification); + } + return lines.join('\n'); + } + /** + * Format coverage report section + */ + formatCoverageReport(coverageReport) { + if (!coverageReport || !coverageReport.available) { + return ''; + } + const lines = []; + lines.push(this.separator()); + lines.push(''); + if (this.mode === 'markdown') { + lines.push('### 📊 Test Coverage Report'); + lines.push(''); + if (coverageReport.overallPercentage !== undefined) { + const emoji = coverageReport.overallPercentage >= 80 ? '🟢' : + coverageReport.overallPercentage >= 60 ? '🟡' : '🔴'; + lines.push(`${emoji} Overall Coverage: **${coverageReport.overallPercentage.toFixed(1)}%**`); + } + if (coverageReport.lineCoverage !== undefined) { + lines.push(`- Lines: ${coverageReport.lineCoverage.toFixed(1)}%`); + } + if (coverageReport.branchCoverage !== undefined) { + lines.push(`- Branches: ${coverageReport.branchCoverage.toFixed(1)}%`); + } + if (coverageReport.delta !== undefined) { + const deltaEmoji = coverageReport.delta >= 0 ? '📈' : '📉'; + lines.push(`${deltaEmoji} Coverage Delta: ${coverageReport.delta >= 0 ? '+' : ''}${coverageReport.delta.toFixed(1)}%`); + } + } + else { + lines.push(chalk.green.bold('📊 Test Coverage Report')); + lines.push(''); + if (coverageReport.overallPercentage !== undefined) { + const emoji = coverageReport.overallPercentage >= 80 ? '🟢' : + coverageReport.overallPercentage >= 60 ? '🟡' : '🔴'; + lines.push(chalk.white(` ${emoji} Overall Coverage: ${coverageReport.overallPercentage.toFixed(1)}%`)); + } + if (coverageReport.lineCoverage !== undefined) { + lines.push(chalk.gray(` Lines: ${coverageReport.lineCoverage.toFixed(1)}%`)); + } + if (coverageReport.branchCoverage !== undefined) { + lines.push(chalk.gray(` Branches: ${coverageReport.branchCoverage.toFixed(1)}%`)); + } + if (coverageReport.delta !== undefined) { + const deltaEmoji = coverageReport.delta >= 0 ? '📈' : '📉'; + const deltaColor = coverageReport.delta >= 0 ? chalk.green : chalk.red; + lines.push(deltaColor(` ${deltaEmoji} Coverage Delta: ${coverageReport.delta >= 0 ? '+' : ''}${coverageReport.delta.toFixed(1)}%`)); + } + } + if (coverageReport.coverageTool) { + lines.push(''); + lines.push(this.dim(`Tool: ${coverageReport.coverageTool}`)); + } + lines.push(''); + return lines.join('\n'); + } + /** + * Format DevOps cost estimates section + */ + formatDevOpsCostEstimates(costEstimates) { + if (!costEstimates || costEstimates.length === 0) { + return ''; + } + const lines = []; + lines.push(this.separator()); + lines.push(''); + if (this.mode === 'markdown') { + lines.push('## 💰 DevOps Cost Estimates'); + lines.push(''); + const totalCost = costEstimates.reduce((sum, e) => sum + (e.estimatedMonthlyCost || 0), 0); + lines.push(`**Total Estimated Monthly Cost:** $${totalCost.toFixed(2)}`); + lines.push(''); + for (const estimate of costEstimates) { + lines.push(`### ${estimate.resourceType || 'Resource'}`); + if (estimate.file) { + lines.push(`File: \`${estimate.file}\``); + } + if (estimate.resourceName) { + lines.push(`Name: **${estimate.resourceName}**`); + } + if (estimate.estimatedMonthlyCost !== undefined) { + lines.push(`Estimated Cost: **$${estimate.estimatedMonthlyCost.toFixed(2)}/month**`); + } + if (estimate.notes) { + lines.push(`Notes: ${estimate.notes}`); + } + lines.push(''); + } + } + else { + lines.push(chalk.yellow.bold('💰 DevOps Cost Estimates')); + lines.push(''); + const totalCost = costEstimates.reduce((sum, e) => sum + (e.estimatedMonthlyCost || 0), 0); + lines.push(chalk.white(` Total Estimated Monthly Cost: $${totalCost.toFixed(2)}`)); + lines.push(''); + for (const estimate of costEstimates) { + lines.push(chalk.cyan(` ${estimate.resourceType || 'Resource'}`)); + if (estimate.file) { + lines.push(chalk.gray(` File: ${estimate.file}`)); + } + if (estimate.resourceName) { + lines.push(chalk.white(` Name: ${estimate.resourceName}`)); + } + if (estimate.estimatedMonthlyCost !== undefined) { + lines.push(chalk.white(` Estimated Cost: $${estimate.estimatedMonthlyCost.toFixed(2)}/month`)); + } + if (estimate.notes) { + lines.push(chalk.gray(` Notes: ${estimate.notes}`)); + } + lines.push(''); + } + } + lines.push(''); + return lines.join('\n'); + } + /** + * Format static analysis section + */ + formatStaticAnalysis(staticAnalysis) { + if (!staticAnalysis) { + return ''; + } + const lines = []; + // Project classification + if (staticAnalysis.projectClassification) { + lines.push(this.formatProjectClassification(staticAnalysis.projectClassification)); + } + // Test suggestions + if (staticAnalysis.testSuggestions) { + lines.push(this.formatTestSuggestions(staticAnalysis.testSuggestions)); + } + // DevOps cost estimates + if (staticAnalysis.devOpsCostEstimates) { + lines.push(this.formatDevOpsCostEstimates(staticAnalysis.devOpsCostEstimates)); + } + // Coverage report + if (staticAnalysis.coverageReport) { + lines.push(this.formatCoverageReport(staticAnalysis.coverageReport)); + } + return lines.join('\n'); + } +} +//# sourceMappingURL=output-formatter.js.map \ No newline at end of file diff --git a/dist/utils/output-formatter.js.map b/dist/utils/output-formatter.js.map new file mode 100644 index 0000000..f59a199 --- /dev/null +++ b/dist/utils/output-formatter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"output-formatter.js","sourceRoot":"","sources":["../../src/utils/output-formatter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B;;GAEG;AACH,MAAM,OAAO,eAAe;IAClB,IAAI,CAAa;IACjB,OAAO,CAAU;IAEzB,YAAY,OAAyB;QACnC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,SAAS;QACP,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;IAChE,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,IAAY;QACf,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,OAAO,KAAK,IAAI,IAAI,CAAC;QACvB,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAY,EAAE,QAAsD,MAAM;QAC9E,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,OAAO,MAAM,IAAI,EAAE,CAAC;QACtB,CAAC;QACD,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;QACrC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,IAAY;QACf,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,IAAY;QACd,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,qBAAqB,CAAC,eAAsB;QAC1C,IAAI,CAAC,eAAe,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QACtE,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAEzE,uBAAuB;QACvB,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC7B,KAAK,CAAC,IAAI,CAAC,4BAA4B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YAC7D,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,QAAQ,CAAC,MAAM,oBAAoB,CAAC,CAAC,CAAC;YAC7F,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,KAAK,MAAM,UAAU,IAAI,QAAQ,EAAE,CAAC;gBAClC,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;oBAC7B,KAAK,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;oBACxC,KAAK,CAAC,IAAI,CAAC,gBAAgB,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;oBACvD,IAAI,UAAU,CAAC,YAAY,EAAE,CAAC;wBAC5B,KAAK,CAAC,IAAI,CAAC,qBAAqB,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC;oBAC7D,CAAC;oBACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACjB,CAAC;qBAAM,CAAC;oBACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;oBACrD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;oBACtE,IAAI,UAAU,CAAC,YAAY,EAAE,CAAC;wBAC5B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,6BAA6B,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;oBACjF,CAAC;oBACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;oBAC1D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBAEf,sCAAsC;oBACtC,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;wBACxB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;wBAC1E,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBAC/D,SAAS,CAAC,OAAO,CAAC,CAAC,IAAY,EAAE,EAAE;4BACjC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;wBACxD,CAAC,CAAC,CAAC;wBACH,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;4BAChD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC,CAAC;wBAC9D,CAAC;wBACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;wBAC1E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACjB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,+BAA+B;QAC/B,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC7B,KAAK,CAAC,IAAI,CAAC,wCAAwC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;YAC7E,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,oCAAoC,YAAY,CAAC,MAAM,8BAA8B,CAAC,CAAC,CAAC;YACtH,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,KAAK,MAAM,UAAU,IAAI,YAAY,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,UAAU,CAAC,gBAAgB,IAAI,UAAU,CAAC,YAAY,CAAC;gBAExE,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;oBAC7B,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC;oBAC9B,KAAK,CAAC,IAAI,CAAC,aAAa,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC9C,KAAK,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;oBAC1C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACjB,CAAC;qBAAM,CAAC;oBACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,QAAQ,EAAE,CAAC,CAAC,CAAC;oBAC3C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;oBAC7D,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;oBAC1D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBAEf,sCAAsC;oBACtC,IAAI,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;wBACtD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;wBAC1E,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBAC/D,SAAS,CAAC,OAAO,CAAC,CAAC,IAAY,EAAE,EAAE;4BACjC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;wBACxD,CAAC,CAAC,CAAC;wBACH,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;4BAChD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC,CAAC;wBACrE,CAAC;wBACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;wBAC1E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACjB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,2BAA2B,CAAC,cAAkC;QAC5D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAE7B,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,6DAA6D;YAC7D,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC7B,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,cAAmB;QACtC,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;YACjD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEf,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;YAC1C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,IAAI,cAAc,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;gBACnD,MAAM,KAAK,GAAG,cAAc,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;oBAChD,cAAc,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;gBAClE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,wBAAwB,cAAc,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC/F,CAAC;YAED,IAAI,cAAc,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC9C,KAAK,CAAC,IAAI,CAAC,YAAY,cAAc,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACpE,CAAC;YAED,IAAI,cAAc,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;gBAChD,KAAK,CAAC,IAAI,CAAC,eAAe,cAAc,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACzE,CAAC;YAED,IAAI,cAAc,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACvC,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC3D,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,oBAAoB,cAAc,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACzH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,IAAI,cAAc,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;gBACnD,MAAM,KAAK,GAAG,cAAc,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;oBAChD,cAAc,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;gBAClE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,sBAAsB,cAAc,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1G,CAAC;YAED,IAAI,cAAc,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC9C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,cAAc,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACnF,CAAC;YAED,IAAI,cAAc,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;gBAChD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,cAAc,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACxF,CAAC;YAED,IAAI,cAAc,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACvC,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC3D,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;gBACvE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,UAAU,oBAAoB,cAAc,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACvI,CAAC;QACH,CAAC;QAED,IAAI,cAAc,CAAC,YAAY,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAC/D,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,yBAAyB,CAAC,aAAoB;QAC5C,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEf,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;YAC1C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3F,KAAK,CAAC,IAAI,CAAC,sCAAsC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACzE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,KAAK,MAAM,QAAQ,IAAI,aAAa,EAAE,CAAC;gBACrC,KAAK,CAAC,IAAI,CAAC,OAAO,QAAQ,CAAC,YAAY,IAAI,UAAU,EAAE,CAAC,CAAC;gBACzD,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;oBAClB,KAAK,CAAC,IAAI,CAAC,WAAW,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC;gBAC3C,CAAC;gBACD,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;oBAC1B,KAAK,CAAC,IAAI,CAAC,WAAW,QAAQ,CAAC,YAAY,IAAI,CAAC,CAAC;gBACnD,CAAC;gBACD,IAAI,QAAQ,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;oBAChD,KAAK,CAAC,IAAI,CAAC,sBAAsB,QAAQ,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;gBACvF,CAAC;gBACD,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACnB,KAAK,CAAC,IAAI,CAAC,UAAU,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;gBACzC,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAC;YAC1D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3F,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,oCAAoC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,KAAK,MAAM,QAAQ,IAAI,aAAa,EAAE,CAAC;gBACrC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,YAAY,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC;gBACnE,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;oBAClB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;gBACxD,CAAC;gBACD,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;oBAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;gBACjE,CAAC;gBACD,IAAI,QAAQ,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;oBAChD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,yBAAyB,QAAQ,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACrG,CAAC;gBACD,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACnB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC1D,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,cAAmB;QACtC,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,yBAAyB;QACzB,IAAI,cAAc,CAAC,qBAAqB,EAAE,CAAC;YACzC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,2BAA2B,CAAC,cAAc,CAAC,qBAAqB,CAAC,CAAC,CAAC;QACrF,CAAC;QAED,mBAAmB;QACnB,IAAI,cAAc,CAAC,eAAe,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,CAAC;QACzE,CAAC;QAED,wBAAwB;QACxB,IAAI,cAAc,CAAC,mBAAmB,EAAE,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,yBAAyB,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC;QACjF,CAAC;QAED,kBAAkB;QAClB,IAAI,cAAc,CAAC,cAAc,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC;QACvE,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF"} \ No newline at end of file diff --git a/docs/MCP-SERVER.md b/docs/MCP-SERVER.md new file mode 100644 index 0000000..056972c --- /dev/null +++ b/docs/MCP-SERVER.md @@ -0,0 +1,356 @@ +# PR Agent MCP Server + +The PR Agent MCP (Model Context Protocol) Server mirrors the CLI workflow exactly, providing LLM-agnostic PR analysis for any MCP-compatible tool. + +## Key Features + +- **Mirrors CLI Exactly**: Same workflow, same configuration, same output format +- **LLM-Agnostic**: No API keys required - uses the calling tool's LLM +- **Same Config File**: Uses `.pragent.config.json` just like the CLI +- **Full Feature Support**: Jira peer review, arch-docs, all CLI options +- **Web Dashboard**: Built-in dashboard for analysis history + +## How It Works + +The MCP server does everything the CLI does **except** calling AI providers: + +1. **Parses git diff** (same as CLI) +2. **Detects risks** using pattern matching (same patterns as CLI) +3. **Calculates complexity** algorithmically (same algorithm as CLI) +4. **Loads arch-docs** if available (same as CLI) +5. **Extracts Jira tickets** from PR title/branch (same as CLI) +6. **Saves to database** for dashboard (same as CLI) +7. **Returns formatted output** for the calling LLM to enhance + +The calling tool's LLM (Claude Code, Cursor, etc.) then adds AI-powered insights to the analysis. + +## Installation + +### Option 1: Global Installation (Recommended) + +```bash +npm install -g @techdebtgpt/pr-agent +``` + +### Option 2: From Source + +```bash +git clone https://github.com/techdebtgpt/pr-agent.git +cd pr-agent +npm install --legacy-peer-deps +npm run build +``` + +## Configuration + +### Claude Code + +Add to your Claude Code settings: + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "pr-agent-mcp" + } + } +} +``` + +Or from source: + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "node", + "args": ["dist/mcp/server.js"] + } + } +} +``` + +### Cursor / Cline / Windsurf + +Same configuration format as Claude Code. + +## Available Tools + +### `analyze` + +Main entry point - mirrors `pr-agent analyze` CLI command exactly. + +**Parameters:** +| Parameter | Type | Description | +|-----------|------|-------------| +| `branch` | string | Base branch to compare (default: auto-detected) | +| `staged` | boolean | Analyze staged changes instead | +| `title` | string | PR title (auto-detected from git) | +| `cwd` | string | Working directory | +| `verbose` | boolean | Include debug info | +| `peerReview` | boolean | Enable Jira validation (uses config if not set) | +| `archDocs` | boolean | Include arch-docs context (uses config if not set) | + +**Example:** +``` +Analyze my current branch changes +``` + +### `dashboard` + +Start the web dashboard - mirrors `pr-agent dashboard` CLI command. + +**Parameters:** +| Parameter | Type | Description | +|-----------|------|-------------| +| `port` | number | Port to run on (default: 3000) | + +**Example:** +``` +Start the PR Agent dashboard +``` + +## Configuration File + +The MCP server uses the same `.pragent.config.json` as the CLI: + +```json +{ + "ai": { + "provider": "anthropic", + "model": "claude-sonnet-4-5-20250929" + }, + "analysis": { + "language": "typescript", + "framework": "react", + "enableStaticAnalysis": true + }, + "git": { + "defaultBranch": "origin/main" + }, + "peerReview": { + "enabled": true, + "provider": "jira", + "instanceUrl": "https://your-company.atlassian.net", + "email": "your-email@company.com", + "apiToken": "your-jira-api-token", + "defaultProject": "PROJ" + } +} +``` + +**Note**: The `ai.provider` and `apiKeys` sections are ignored by the MCP server since it's LLM-agnostic. The calling tool provides the AI. + +## Output Format + +The MCP server returns output formatted exactly like the CLI: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +✨ PR Agent Analysis Complete! + +📋 Summary + +Title: Add new authentication system +Repository: owner/repo +Branch: feature/auth → origin/main +Files changed: 5 +Lines: +234 / -45 +Languages: TypeScript + +📊 Complexity + +Score: 3/5 - Moderate complexity - ensure thorough testing +Total changes: 279 lines +Files: 5 +⚙️ Contains config changes + +⚠️ Detected Risks + + 1. 🔴 [CRITICAL] Potential hardcoded API key detected + 2. 🟡 [WARNING] Use of eval() detected - potential code injection risk + +📁 Files Changed + + 📝 src/auth/login.ts (+120/-20) + 📝 src/auth/logout.ts (+45/-10) + ➕ src/auth/middleware.ts (+69/-0) + 📝 config/auth.json (+0/-15) + +🎫 Linked Tickets + + • AUTH-123 (from branch, confidence: 85%) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +📝 INSTRUCTIONS FOR AI ANALYSIS: + +Please analyze this PR and provide: +1. A brief summary of what the changes do +2. Potential risks or issues (bugs, edge cases, security) +3. Recommendations for improvement +4. Validation against linked ticket requirements (if Jira access available) + +Format your response like the PR Agent CLI output shown above. +``` + +## Peer Review (Jira Integration) + +If you have Jira configured in `.pragent.config.json`, the MCP server will: + +1. **Extract ticket references** from PR title, branch name, and commits +2. **Report linked tickets** in the analysis output +3. **Enable peer review** validation by the calling LLM + +The calling LLM can then use Jira MCP tools (if available) to: +- Fetch ticket details and acceptance criteria +- Validate implementation against requirements +- Provide senior-dev style verdict + +## Architecture Documentation + +If your repository has a `.arch-docs` folder, the MCP server will: + +1. **Load all architecture documentation** +2. **Find relevant sections** based on changed files +3. **Include context** in the analysis output + +This helps the calling LLM understand your codebase patterns. + +## Web Dashboard + +The dashboard shows: +- **PR analysis history** +- **Code quality trends** +- **ROI metrics** +- **Recent activity** + +Data is stored in `pr-agent.db` (SQLite) - same database as CLI. + +## Comparison: CLI vs MCP Server + +| Feature | CLI | MCP Server | +|---------|-----|------------| +| Config file | `.pragent.config.json` | `.pragent.config.json` | +| Diff parsing | ✅ | ✅ | +| Risk detection | ✅ | ✅ | +| Complexity scoring | ✅ | ✅ | +| Arch-docs support | ✅ | ✅ | +| Jira ticket extraction | ✅ | ✅ | +| Dashboard | ✅ | ✅ | +| Database storage | ✅ | ✅ | +| AI analysis | Requires API key | Uses calling LLM | +| Peer review AI | Requires API key | Uses calling LLM | + +## Troubleshooting + +### MCP Server Not Starting + +```bash +# Test manually +node dist/mcp/server.js + +# Check for errors +pr-agent-mcp 2>&1 +``` + +### Config Not Loading + +The MCP server looks for `.pragent.config.json` in: +1. Current working directory +2. Parent directories (up to root) + +### Dashboard Port in Use + +``` +Start the dashboard on port 3001 +``` + +### No Changes Detected + +Make sure you're in a git repository with uncommitted changes or on a branch that differs from the base branch. + +## Publishing + +### Publishing to npm + +The MCP server is published as part of the `@techdebtgpt/pr-agent` npm package: + +```bash +# Login to npm +npm login + +# Publish (runs build automatically via prepublishOnly) +npm publish --access public +``` + +### Publishing to MCP Registry + +The MCP Registry is the official directory for Model Context Protocol servers. + +1. **Ensure `server.json` is valid** - Located in project root with proper schema +2. **Install the Publisher CLI**: + ```bash + brew install mcp-publisher # macOS + # Or download from releases + ``` +3. **Authenticate with GitHub**: + ```bash + mcp-publisher login github + ``` +4. **Publish**: + ```bash + mcp-publisher publish + ``` + +The `mcpName` field in `package.json` (`io.github.techdebtgpt/pr-agent`) enables automatic registry validation. + +### Publishing to Smithery + +[Smithery](https://smithery.ai) is a marketplace for MCP servers. + +1. **Connect your GitHub repository** at smithery.ai +2. **Ensure `smithery.json` exists** in project root +3. **Start a deployment** from the Smithery dashboard +4. Your server becomes discoverable at smithery.ai + +### Automatic Installation + +Once published, users can install via: + +**Smithery:** +```bash +smithery install @techdebtgpt/pr-agent +``` + +**npx (direct):** +```bash +npx -y @techdebtgpt/pr-agent mcp +``` + +**Manual configuration:** +```json +{ + "mcpServers": { + "pr-agent": { + "command": "npx", + "args": ["-y", "@techdebtgpt/pr-agent", "mcp"] + } + } +} +``` + +## Security Considerations + +Following MCP best practices: + +- **No external API calls** - Server runs locally, LLM-agnostic +- **Credential safety** - Config files stay local, use env vars for secrets +- **Tool annotations** - `readOnlyHint: true` on analyze tool +- **Input validation** - All parameters validated with Zod schemas +- **Secure defaults** - Dashboard binds to localhost only + +## License + +Apache-2.0 License - see [LICENSE](../LICENSE) for details. diff --git a/jest.config.js b/jest.config.js index 31c4ca4..22b3bfa 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,5 @@ export default { - preset: 'ts-jest', + preset: 'ts-jest/presets/default-esm', testEnvironment: 'node', roots: ['/src', '/tests'], testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'], @@ -8,9 +8,11 @@ export default { transform: { '^.+\\.ts$': ['ts-jest', { useESM: true, - isolatedModules: true, - diagnostics: { - ignoreCodes: [151002], + tsconfig: { + module: 'nodenext', + moduleResolution: 'nodenext', + target: 'ES2022', + esModuleInterop: true, }, }], }, diff --git a/package-lock.json b/package-lock.json index 36d9467..d03c9a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,26 +17,33 @@ "@langchain/google-genai": "^2.0.0", "@langchain/langgraph": "^1.0.2", "@langchain/openai": "^1.1.3", + "@modelcontextprotocol/sdk": "^1.25.2", "@octokit/rest": "^22.0.1", + "better-sqlite3": "^12.5.0", "chalk": "^4.1.2", "commander": "^14.0.2", "inquirer": "^12.10.0", "langchain": "^1.1.1", + "open": "^11.0.0", "ora": "^9.0.0", - "probot": "^12.3.1" + "probot": "^12.3.1", + "zod": "^3.23.8" }, "bin": { - "pr-agent": "dist/cli/index.js" + "pr-agent": "dist/cli/index.js", + "pr-agent-mcp": "dist/mcp/server.js" }, "devDependencies": { + "@types/better-sqlite3": "^7.6.13", "@types/jest": "^29.5.12", "@types/node": "^24.7.1", "@vercel/ncc": "^0.38.4", "jest": "^29.7.0", + "nyc": "^17.1.0", "ts-jest": "^29.1.2", + "ts-node": "^10.9.2", "tsx": "^4.0.0", - "typescript": "^5.2.2", - "zod": "^4.1.13" + "typescript": "^5.2.2" }, "engines": { "node": ">=18.0.0" @@ -76,6 +83,101 @@ "undici": "^5.28.5" } }, + "node_modules/@actions/github/node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@actions/github/node_modules/@octokit/core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", + "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.4.1", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@actions/github/node_modules/@octokit/graphql": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", + "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", + "license": "MIT", + "dependencies": { + "@octokit/request": "^8.4.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@actions/github/node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", + "license": "MIT" + }, + "node_modules/@actions/github/node_modules/@octokit/plugin-paginate-rest": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz", + "integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@actions/github/node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, + "node_modules/@actions/github/node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz", + "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@actions/github/node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, "node_modules/@actions/http-client": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", @@ -124,13 +226,13 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -139,9 +241,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", "dev": true, "license": "MIT", "engines": { @@ -149,21 +251,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -180,14 +282,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -197,13 +299,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -224,29 +326,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -256,9 +358,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { @@ -296,27 +398,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.28.6" }, "bin": { "parser": "bin/babel-parser.js" @@ -381,13 +483,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -423,13 +525,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -549,13 +651,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -565,42 +667,42 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", "debug": "^4.3.1" }, "engines": { @@ -608,9 +710,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { @@ -634,10 +736,34 @@ "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==", "license": "MIT" }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz", - "integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -652,9 +778,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.0.tgz", - "integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -669,9 +795,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz", - "integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -686,9 +812,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.0.tgz", - "integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -703,9 +829,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz", - "integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -720,9 +846,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz", - "integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -737,9 +863,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz", - "integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -754,9 +880,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz", - "integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -771,9 +897,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz", - "integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -788,9 +914,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz", - "integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -805,9 +931,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz", - "integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -822,9 +948,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz", - "integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -839,9 +965,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz", - "integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -856,9 +982,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz", - "integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -873,9 +999,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz", - "integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -890,9 +1016,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz", - "integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -907,9 +1033,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz", - "integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -924,9 +1050,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz", - "integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", "cpu": [ "arm64" ], @@ -941,9 +1067,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz", - "integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -958,9 +1084,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz", - "integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", "cpu": [ "arm64" ], @@ -975,9 +1101,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz", - "integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -992,9 +1118,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz", - "integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", "cpu": [ "arm64" ], @@ -1009,9 +1135,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz", - "integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -1026,9 +1152,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz", - "integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -1043,9 +1169,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz", - "integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -1060,9 +1186,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz", - "integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -1100,6 +1226,18 @@ "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==", "license": "BSD-3-Clause" }, + "node_modules/@hono/node-server": { + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.8.tgz", + "integrity": "sha512-0/g2lIOPzX8f3vzW1ggQgvG5mjtFBDBHFAzI5SFAi2DzSqS9luJwqg9T6O/gKYLi+inS7eNxBeIFkkghIPvrMA==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@inquirer/ansi": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", @@ -1820,24 +1958,25 @@ } }, "node_modules/@langchain/anthropic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@langchain/anthropic/-/anthropic-1.1.3.tgz", - "integrity": "sha512-vJN7Rfl+8lDO+aVFfccDUFxIMwGtf8xHSWvqmeytOB5UBzGxNMRW2Zdu6Gv8vWrKlS6Ca7/8oB1suw1SN0FKGA==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@langchain/anthropic/-/anthropic-1.3.7.tgz", + "integrity": "sha512-tuj877NsygqpQXdv1QCnhcycRNntZnv8S86oY4/0TEkq4aKqyB8VfCcKxcf03EdKufdPkF6phmWY59czV2CM0g==", "license": "MIT", "dependencies": { - "@anthropic-ai/sdk": "^0.71.0" + "@anthropic-ai/sdk": "^0.71.0", + "zod": "^3.25.76 || ^4" }, "engines": { "node": ">=20" }, "peerDependencies": { - "@langchain/core": "^1.0.0" + "@langchain/core": "1.1.12" } }, "node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk": { - "version": "0.71.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.0.tgz", - "integrity": "sha512-go1XeWXmpxuiTkosSXpb8tokLk2ZLkIRcXpbWVwJM6gH5OBtHOVsfPfGuqI1oW7RRt4qc59EmYbrXRZ0Ng06Jw==", + "version": "0.71.2", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.2.tgz", + "integrity": "sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==", "license": "MIT", "dependencies": { "json-schema-to-ts": "^3.1.1" @@ -1855,9 +1994,9 @@ } }, "node_modules/@langchain/core": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@langchain/core/-/core-1.1.0.tgz", - "integrity": "sha512-yJ6JHcU9psjnQbzRFkXjIdNTA+3074dA+2pHdH8ewvQCSleSk6JcjkCMIb5+NASjeMoi1ZuntlLKVsNqF38YxA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@langchain/core/-/core-1.1.12.tgz", + "integrity": "sha512-sHWLvhyLi3fntlg3MEPB89kCjxEX7/+imlIYJcp6uFGCAZfGxVWklqp22HwjT1szorUBYrkO8u0YA554ReKxGQ==", "license": "MIT", "dependencies": { "@cfworker/json-schema": "^4.0.2", @@ -1865,10 +2004,9 @@ "camelcase": "6", "decamelize": "1.2.0", "js-tiktoken": "^1.0.12", - "langsmith": "^0.3.64", + "langsmith": ">=0.4.0 <1.0.0", "mustache": "^4.2.0", "p-queue": "^6.6.2", - "p-retry": "^7.0.0", "uuid": "^10.0.0", "zod": "^3.25.76 || ^4" }, @@ -1877,9 +2015,9 @@ } }, "node_modules/@langchain/google-genai": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@langchain/google-genai/-/google-genai-2.0.0.tgz", - "integrity": "sha512-PaAWkogQdF+Y2bhhXWXUrC2nO7sTgWLtobBbZl/0V8Aa1F/KG2wrMECie3S17bAdFu/6VmQOuFFrlgSMwQC5KA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@langchain/google-genai/-/google-genai-2.1.7.tgz", + "integrity": "sha512-K63TGK0XlhUkhy+Vt1SRBfVIa+sq5bTfZF56zL+Wey/mR9VZx60gBCtIBofTa3wlQuPZzLtMZaawKRN3cWXlqw==", "license": "MIT", "dependencies": { "@google/generative-ai": "^0.24.0", @@ -1889,7 +2027,7 @@ "node": ">=20" }, "peerDependencies": { - "@langchain/core": "1.1.0" + "@langchain/core": "1.1.12" } }, "node_modules/@langchain/google-genai/node_modules/uuid": { @@ -1906,13 +2044,13 @@ } }, "node_modules/@langchain/langgraph": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@langchain/langgraph/-/langgraph-1.0.2.tgz", - "integrity": "sha512-syxzzWTnmpCL+RhUEvalUeOXFoZy/KkzHa2Da2gKf18zsf9Dkbh3rfnRDrTyUGS1XSTejq07s4rg1qntdEDs2A==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@langchain/langgraph/-/langgraph-1.0.15.tgz", + "integrity": "sha512-l7/f255sPilanhyY+lbX+VDXQSnytFwJ4FVoEl4OBpjDoCHuDyHUL5yrb568apBSHgQA7aKsYac0mBEqIR5Bjg==", "license": "MIT", "dependencies": { "@langchain/langgraph-checkpoint": "^1.0.0", - "@langchain/langgraph-sdk": "~1.0.0", + "@langchain/langgraph-sdk": "~1.5.0", "uuid": "^10.0.0" }, "engines": { @@ -1945,14 +2083,14 @@ } }, "node_modules/@langchain/langgraph-sdk": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-1.0.3.tgz", - "integrity": "sha512-6M4i0XsVO5Eb2vv/3OtIPHW3UqO4zYyXl6AOfS0Jf6d7JiWiSXqzLN8UoS0hpu1ItkcW1j575CRiP/6jn6XXFg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-1.5.3.tgz", + "integrity": "sha512-8ycRjOGsBafxvCpHyCGaWhd3s7UEXEYIEPO/vipebEzQuYaeF+E9MxS9uFSVaX1ZcNuqQNTosnBJG4ZUtirzuw==", "license": "MIT", "dependencies": { - "p-queue": "^6.6.2", - "p-retry": "4", - "uuid": "^9.0.0" + "p-queue": "^9.0.1", + "p-retry": "^7.1.1", + "uuid": "^13.0.0" }, "peerDependencies": { "@langchain/core": "^1.0.1", @@ -1971,40 +2109,61 @@ } } }, - "node_modules/@langchain/langgraph-sdk/node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "node_modules/@langchain/langgraph-sdk/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/@langchain/langgraph-sdk/node_modules/p-queue": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.1.0.tgz", + "integrity": "sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==", "license": "MIT", "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" + "eventemitter3": "^5.0.1", + "p-timeout": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@langchain/langgraph-sdk/node_modules/p-timeout": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", + "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@langchain/langgraph-sdk/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/@langchain/openai": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-1.1.3.tgz", - "integrity": "sha512-p+xR+4HRms5Ozjf5miC6U2AYRyNVSTdO7AMBkMYs1Tp6DWHBd+mQ72H8Ogd2dKrPuS5UDJ5dbpI1fS+OrTbgQQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-1.2.1.tgz", + "integrity": "sha512-eZYPhvXIwz0/8iCjj2LWqeaznQ7DZ6tBdvF+Ebv4sQW2UqJWZqRC8QIdKZgTbs8ffMWPHkSSOidYqu4XfWCNYg==", "license": "MIT", "dependencies": { "js-tiktoken": "^1.0.12", - "openai": "^6.9.0", + "openai": "^6.10.0", "zod": "^3.25.76 || ^4" }, "engines": { @@ -2014,6 +2173,45 @@ "@langchain/core": "^1.0.0" } }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.25.2", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.2.tgz", + "integrity": "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.7", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, "node_modules/@octokit/auth-app": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-4.0.13.tgz", @@ -2334,12 +2532,12 @@ } }, "node_modules/@octokit/auth-token": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", - "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@octokit/auth-unauthenticated": { @@ -2385,78 +2583,208 @@ } }, "node_modules/@octokit/core": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", - "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", + "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", "license": "MIT", "dependencies": { - "@octokit/auth-token": "^4.0.0", - "@octokit/graphql": "^7.1.0", - "@octokit/request": "^8.4.1", - "@octokit/request-error": "^5.1.1", - "@octokit/types": "^13.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.3", + "@octokit/request": "^10.0.6", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" }, "engines": { - "node": ">= 18" + "node": ">= 20" } }, - "node_modules/@octokit/endpoint": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", - "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "node_modules/@octokit/core/node_modules/@octokit/endpoint": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.2.tgz", + "integrity": "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==", "license": "MIT", "dependencies": { - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.2" }, "engines": { - "node": ">= 18" + "node": ">= 20" } }, - "node_modules/@octokit/graphql": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", - "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", + "node_modules/@octokit/core/node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "license": "MIT" + }, + "node_modules/@octokit/core/node_modules/@octokit/request": { + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.7.tgz", + "integrity": "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==", "license": "MIT", "dependencies": { - "@octokit/request": "^8.4.1", - "@octokit/types": "^13.0.0", - "universal-user-agent": "^6.0.0" + "@octokit/endpoint": "^11.0.2", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" }, "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/oauth-authorization-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-5.0.0.tgz", - "integrity": "sha512-y1WhN+ERDZTh0qZ4SR+zotgsQUE1ysKnvBt1hvDRB2WRzYtVKQjn97HEPzoehh66Fj9LwNdlZh+p6TJatT0zzg==", - "license": "MIT", - "engines": { - "node": ">= 14" + "node": ">= 20" } }, - "node_modules/@octokit/oauth-methods": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-2.0.6.tgz", - "integrity": "sha512-l9Uml2iGN2aTWLZcm8hV+neBiFXAQ9+3sKiQe/sgumHlL6HDg0AQ8/l16xX/5jJvfxueqTW5CWbzd0MjnlfHZw==", + "node_modules/@octokit/core/node_modules/@octokit/request-error": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", + "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", "license": "MIT", "dependencies": { - "@octokit/oauth-authorization-url": "^5.0.0", - "@octokit/request": "^6.2.3", - "@octokit/request-error": "^3.0.3", - "@octokit/types": "^9.0.0", - "btoa-lite": "^1.0.0" + "@octokit/types": "^16.0.0" }, "engines": { - "node": ">= 14" + "node": ">= 20" } }, - "node_modules/@octokit/oauth-methods/node_modules/@octokit/endpoint": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", + "node_modules/@octokit/core/node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/@octokit/core/node_modules/before-after-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "license": "Apache-2.0" + }, + "node_modules/@octokit/core/node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", + "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", + "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.6", + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql/node_modules/@octokit/endpoint": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.2.tgz", + "integrity": "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "license": "MIT" + }, + "node_modules/@octokit/graphql/node_modules/@octokit/request": { + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.7.tgz", + "integrity": "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.2", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql/node_modules/@octokit/request-error": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", + "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql/node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/@octokit/graphql/node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + }, + "node_modules/@octokit/oauth-authorization-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-5.0.0.tgz", + "integrity": "sha512-y1WhN+ERDZTh0qZ4SR+zotgsQUE1ysKnvBt1hvDRB2WRzYtVKQjn97HEPzoehh66Fj9LwNdlZh+p6TJatT0zzg==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/oauth-methods": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-2.0.6.tgz", + "integrity": "sha512-l9Uml2iGN2aTWLZcm8hV+neBiFXAQ9+3sKiQe/sgumHlL6HDg0AQ8/l16xX/5jJvfxueqTW5CWbzd0MjnlfHZw==", + "license": "MIT", + "dependencies": { + "@octokit/oauth-authorization-url": "^5.0.0", + "@octokit/request": "^6.2.3", + "@octokit/request-error": "^3.0.3", + "@octokit/types": "^9.0.0", + "btoa-lite": "^1.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/oauth-methods/node_modules/@octokit/endpoint": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", "license": "MIT", "dependencies": { @@ -2556,64 +2884,16 @@ "@octokit/openapi-types": "^12.11.0" } }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz", - "integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^12.6.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", - "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", - "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^20.0.0" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz", - "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", + "node_modules/@octokit/plugin-request-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", + "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", "license": "MIT", - "dependencies": { - "@octokit/types": "^12.6.0" - }, "engines": { - "node": ">= 18" + "node": ">= 20" }, "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", - "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", - "license": "MIT" - }, - "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", - "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^20.0.0" + "@octokit/core": ">=6" } }, "node_modules/@octokit/plugin-retry": { @@ -2685,60 +2965,6 @@ "node": ">= 20" } }, - "node_modules/@octokit/rest/node_modules/@octokit/auth-token": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", - "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/rest/node_modules/@octokit/core": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", - "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", - "license": "MIT", - "dependencies": { - "@octokit/auth-token": "^6.0.0", - "@octokit/graphql": "^9.0.3", - "@octokit/request": "^10.0.6", - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "before-after-hook": "^4.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/rest/node_modules/@octokit/endpoint": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.2.tgz", - "integrity": "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^16.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/rest/node_modules/@octokit/graphql": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", - "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", - "license": "MIT", - "dependencies": { - "@octokit/request": "^10.0.6", - "@octokit/types": "^16.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, "node_modules/@octokit/rest/node_modules/@octokit/openapi-types": { "version": "27.0.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", @@ -2760,18 +2986,6 @@ "@octokit/core": ">=6" } }, - "node_modules/@octokit/rest/node_modules/@octokit/plugin-request-log": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", - "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "@octokit/core": ">=6" - } - }, "node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz", @@ -2787,34 +3001,6 @@ "@octokit/core": ">=6" } }, - "node_modules/@octokit/rest/node_modules/@octokit/request": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.7.tgz", - "integrity": "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==", - "license": "MIT", - "dependencies": { - "@octokit/endpoint": "^11.0.2", - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "fast-content-type-parse": "^3.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/rest/node_modules/@octokit/request-error": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", - "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^16.0.0" - }, - "engines": { - "node": ">= 20" - } - }, "node_modules/@octokit/rest/node_modules/@octokit/types": { "version": "16.0.0", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", @@ -2824,18 +3010,6 @@ "@octokit/openapi-types": "^27.0.0" } }, - "node_modules/@octokit/rest/node_modules/before-after-hook": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", - "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", - "license": "Apache-2.0" - }, - "node_modules/@octokit/rest/node_modules/universal-user-agent": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", - "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", - "license": "ISC" - }, "node_modules/@octokit/types": { "version": "13.10.0", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", @@ -3054,6 +3228,34 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3099,6 +3301,16 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/better-sqlite3": { + "version": "7.6.13", + "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", + "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", @@ -3137,9 +3349,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", - "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", "license": "MIT", "dependencies": { "@types/node": "*", @@ -3240,9 +3452,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", - "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "version": "24.10.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.7.tgz", + "integrity": "sha512-+054pVMzVTmRQV8BhpGv3UyfZ2Llgl8rdpDTon+cUH9+na0ncBVXj3wTUKh14+Kiz18ziM3b4ikpP5/Pc0rQEQ==", "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -3310,12 +3522,6 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "license": "MIT" }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "license": "MIT" - }, "node_modules/@types/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", @@ -3399,18 +3605,44 @@ } }, "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, "engines": { "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agentkeepalive": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", @@ -3436,6 +3668,39 @@ "node": ">=8" } }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -3487,6 +3752,33 @@ "node": ">= 8" } }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -3749,9 +4041,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.32", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.32.tgz", - "integrity": "sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", + "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3764,57 +4056,64 @@ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "license": "Apache-2.0" }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "node_modules/better-sqlite3": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.6.0.tgz", + "integrity": "sha512-FXI191x+D6UPWSze5IzZjhz+i9MK9nsuHsmTX9bXVl52k06AfZ2xql0lrgIUuzsMsJ7Vgl5kIptvDgBLIV3ZSQ==", + "hasInstallScript": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "engines": { + "node": "20.x || 22.x || 23.x || 24.x || 25.x" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "file-uri-to-path": "1.0.0" } }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, "node_modules/bottleneck": { "version": "2.19.5", "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", @@ -3846,9 +4145,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", - "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -3866,11 +4165,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.25", - "caniuse-lite": "^1.0.30001754", - "electron-to-chromium": "^1.5.249", + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", - "update-browserslist-db": "^1.1.4" + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -3908,6 +4207,30 @@ "integrity": "sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA==", "license": "MIT" }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3921,6 +4244,21 @@ "dev": true, "license": "MIT" }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -3930,6 +4268,58 @@ "node": ">= 0.8" } }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/caching-transform/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caching-transform/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/caching-transform/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -3982,9 +4372,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001757", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", - "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", + "version": "1.0.30001764", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz", + "integrity": "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==", "dev": true, "funding": [ { @@ -4067,6 +4457,12 @@ "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", "license": "MIT" }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -4288,6 +4684,13 @@ "node": ">=20" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4305,15 +4708,16 @@ } }, "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -4333,19 +4737,35 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } }, "node_modules/create-jest": { "version": "29.7.0", @@ -4369,11 +4789,17 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -4419,10 +4845,25 @@ "node": ">=0.10.0" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/dedent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", - "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", + "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -4434,6 +4875,15 @@ } } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -4443,6 +4893,62 @@ "node": ">=0.10.0" } }, + "node_modules/default-browser": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", + "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4486,6 +4992,15 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -4496,6 +5011,16 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -4545,9 +5070,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.262", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz", - "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==", + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", "dev": true, "license": "ISC" }, @@ -4642,10 +5167,17 @@ "node": ">= 0.4" } }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz", - "integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4656,32 +5188,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.0", - "@esbuild/android-arm": "0.27.0", - "@esbuild/android-arm64": "0.27.0", - "@esbuild/android-x64": "0.27.0", - "@esbuild/darwin-arm64": "0.27.0", - "@esbuild/darwin-x64": "0.27.0", - "@esbuild/freebsd-arm64": "0.27.0", - "@esbuild/freebsd-x64": "0.27.0", - "@esbuild/linux-arm": "0.27.0", - "@esbuild/linux-arm64": "0.27.0", - "@esbuild/linux-ia32": "0.27.0", - "@esbuild/linux-loong64": "0.27.0", - "@esbuild/linux-mips64el": "0.27.0", - "@esbuild/linux-ppc64": "0.27.0", - "@esbuild/linux-riscv64": "0.27.0", - "@esbuild/linux-s390x": "0.27.0", - "@esbuild/linux-x64": "0.27.0", - "@esbuild/netbsd-arm64": "0.27.0", - "@esbuild/netbsd-x64": "0.27.0", - "@esbuild/openbsd-arm64": "0.27.0", - "@esbuild/openbsd-x64": "0.27.0", - "@esbuild/openharmony-arm64": "0.27.0", - "@esbuild/sunos-x64": "0.27.0", - "@esbuild/win32-arm64": "0.27.0", - "@esbuild/win32-ia32": "0.27.0", - "@esbuild/win32-x64": "0.27.0" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/escalade": { @@ -4748,12 +5280,24 @@ "license": "MIT" }, "node_modules/eventsource": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", - "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" } }, "node_modules/execa": { @@ -4796,6 +5340,15 @@ "node": ">= 0.8.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/expect": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", @@ -4814,45 +5367,42 @@ } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 18" }, "funding": { "type": "opencollective", @@ -4914,21 +5464,21 @@ "node": ">=10" } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, "node_modules/fast-content-type-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", @@ -4945,6 +5495,12 @@ ], "license": "MIT" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -4967,6 +5523,22 @@ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fast-url-parser": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", @@ -4986,6 +5558,12 @@ "bser": "2.1.1" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -5000,37 +5578,59 @@ } }, "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/find-up": { "version": "4.1.0", @@ -5052,6 +5652,23 @@ "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==", "license": "MIT" }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", @@ -5074,6 +5691,27 @@ "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", "license": "MIT" }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/formdata-node": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", @@ -5106,14 +5744,41 @@ } }, "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -5249,6 +5914,12 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -5346,6 +6017,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -5358,6 +6056,16 @@ "node": ">= 0.4" } }, + "node_modules/hono": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.6.tgz", + "integrity": "sha512-ofIiiHyl34SV6AuhE3YT2mhO5HRWokce+eUYE82TsP6z0/H3JeJcjVWEMSIAiw2QkjDOEpES/lYsg8eEbsLtdw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -5366,19 +6074,23 @@ "license": "MIT" }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/human-signals": { @@ -5401,9 +6113,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -5416,6 +6128,26 @@ "url": "https://opencollective.com/express" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -5478,6 +6210,12 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, "node_modules/inquirer": { "version": "12.11.1", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.11.1.tgz", @@ -5505,9 +6243,9 @@ } }, "node_modules/ioredis": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.30.1.tgz", - "integrity": "sha512-17Ed70njJ7wT7JZsdTVLb0j/cmwHwfQCFu+AP6jY7nFKd+CA7MBW7nX121mM64eT8S9ekAVtYYt8nGQPmm3euA==", + "version": "4.31.0", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.31.0.tgz", + "integrity": "sha512-tVrCrc4LWJwX82GD79dZ0teZQGq+5KJEGpXJRgzHOrhHtLgF9ME6rTwDV5+HN5bjnvmtrnS8ioXhflY16sy2HQ==", "license": "MIT", "dependencies": { "@ioredis/commands": "^1.0.2", @@ -5560,6 +6298,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5579,6 +6332,36 @@ "node": ">=6" } }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", @@ -5622,6 +6405,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -5635,6 +6424,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, "node_modules/is-unicode-supported": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", @@ -5647,11 +6443,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -5664,6 +6484,19 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-instrument": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", @@ -5694,6 +6527,47 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "license": "ISC", + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", @@ -6329,6 +7203,15 @@ "node": ">= 0.6.0" } }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", @@ -6406,6 +7289,18 @@ "node": ">=16" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -6420,12 +7315,12 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", "dependencies": { - "jws": "^3.2.2", + "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -6454,9 +7349,9 @@ } }, "node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -6465,12 +7360,12 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -6485,14 +7380,14 @@ } }, "node_modules/langchain": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/langchain/-/langchain-1.1.1.tgz", - "integrity": "sha512-z7cOFhLOzbu/lRlIE8GZ5rlfi7obvvHThhMdts1KsUBusJmWLmh1Yik28MHYzJRXclUbqs4u/9D2yNmr36wf0A==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/langchain/-/langchain-1.2.7.tgz", + "integrity": "sha512-G+3Ftz/08CurJaE7LukQGBf3mCSz7XM8LZeAaFPg391Ru4lT8eLYfG6Fv4ZI0u6EBsPVcOQfaS9ig8nCRmJeqA==", "license": "MIT", "dependencies": { "@langchain/langgraph": "^1.0.0", "@langchain/langgraph-checkpoint": "^1.0.0", - "langsmith": "~0.3.74", + "langsmith": ">=0.4.0 <1.0.0", "uuid": "^10.0.0", "zod": "^3.25.76 || ^4" }, @@ -6500,13 +7395,13 @@ "node": ">=20" }, "peerDependencies": { - "@langchain/core": "1.1.0" + "@langchain/core": "1.1.12" } }, "node_modules/langsmith": { - "version": "0.3.82", - "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.3.82.tgz", - "integrity": "sha512-RTcxtRm0zp2lV+pMesMW7EZSsIlqN7OmR2F6sZ/sOFQwmcLVl+VErMPV4VkX4Sycs4/EIAFT5hpr36EqiHoikQ==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.4.5.tgz", + "integrity": "sha512-9N4JSQLz6fWiZwVXaiy0erlvNHlC68EtGJZG2OX+1y9mqj7KvKSL+xJnbCFc+ky3JN8s1d6sCfyyDdi4uDdLnQ==", "license": "MIT", "dependencies": { "@types/uuid": "^10.0.0", @@ -6656,6 +7551,13 @@ "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "license": "MIT" }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -6793,19 +7695,22 @@ } }, "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", + "engines": { + "node": ">=18" + }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -6853,24 +7758,28 @@ } }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mimic-fn": { @@ -6895,6 +7804,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -6917,6 +7838,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, "node_modules/mri": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", @@ -6950,6 +7877,12 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6958,9 +7891,9 @@ "license": "MIT" }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6972,6 +7905,30 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "license": "MIT" }, + "node_modules/node-abi": { + "version": "3.85.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.85.0.tgz", + "integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -7019,6 +7976,19 @@ "dev": true, "license": "MIT" }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", @@ -7049,6 +8019,181 @@ "node": ">=8" } }, + "node_modules/nyc": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz", + "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^3.3.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^6.0.2", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nyc/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -7137,10 +8282,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openai": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.9.1.tgz", - "integrity": "sha512-vQ5Rlt0ZgB3/BNmTa7bIijYFhz3YBceAA3Z4JuoMSBftBF9YqFHIEhZakSs+O/Ad7EaoEimZvHxD5ylRjN11Lg==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.16.0.tgz", + "integrity": "sha512-fZ1uBqjFUjXzbGc35fFtYKEOxd20kd9fDpFeqWtsOZWiubY8CZ1NAlXHW3iathaFvqmNtCWMIsosCuyeI7Joxg==", "license": "Apache-2.0", "bin": { "openai": "bin/cli" @@ -7300,9 +8465,9 @@ } }, "node_modules/p-retry": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-7.1.0.tgz", - "integrity": "sha512-xL4PiFRQa/f9L9ZvR4/gUCRNus4N8YX80ku8kv9Jqz+ZokkiZLM0bcvX0gm1F3PDi9SPRsww1BDsTWgE6Y1GLQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-7.1.1.tgz", + "integrity": "sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==", "license": "MIT", "dependencies": { "is-network-error": "^1.1.0" @@ -7335,6 +8500,22 @@ "node": ">=6" } }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -7387,7 +8568,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7400,10 +8580,14 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, "node_modules/picocolors": { "version": "1.1.1", @@ -7527,6 +8711,15 @@ "node": ">= 6" } }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/pkg-conf": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", @@ -7598,20 +8791,58 @@ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "license": "MIT", "engines": { - "node": ">=4" + "node": ">=4" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "license": "MIT", "dependencies": { - "find-up": "^4.0.0" + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, "node_modules/pretty-format": { @@ -7935,6 +9166,43 @@ "@octokit/openapi-types": "^14.0.0" } }, + "node_modules/probot/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/probot/node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/probot/node_modules/commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", @@ -7944,6 +9212,133 @@ "node": ">= 6" } }, + "node_modules/probot/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/probot/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/probot/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/probot/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/probot/node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/probot/node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/probot/node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/probot/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/probot/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/probot/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7956,6 +9351,75 @@ "node": ">=10" } }, + "node_modules/probot/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/probot/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/probot/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/probot/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/probot/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/probot/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/probot/node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/probot/node_modules/semver": { "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", @@ -7968,6 +9432,58 @@ "node": ">=10" } }, + "node_modules/probot/node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/probot/node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/probot/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/probot/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -7983,6 +9499,19 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" }, + "node_modules/process-on-spawn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", + "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/process-warning": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", @@ -8050,12 +9579,12 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -8080,28 +9609,40 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8142,7 +9683,20 @@ "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", "license": "MIT", "dependencies": { - "redis-errors": "^1.0.0" + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "license": "ISC", + "dependencies": { + "es6-error": "^4.0.1" }, "engines": { "node": ">=4" @@ -8158,6 +9712,22 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -8252,21 +9822,57 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "license": "MIT" }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-async": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", @@ -8322,68 +9928,57 @@ } }, "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -8394,7 +9989,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -8407,7 +10001,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8497,6 +10090,51 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-wcswidth": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.1.2.tgz", @@ -8549,6 +10187,61 @@ "source-map": "^0.6.0" } }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/spawn-wrap/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/spawn-wrap/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -8584,9 +10277,9 @@ "license": "MIT" }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -8738,6 +10431,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -8795,9 +10516,9 @@ "license": "MIT" }, "node_modules/ts-jest": { - "version": "29.4.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz", - "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", "dev": true, "license": "MIT", "dependencies": { @@ -8873,6 +10594,50 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -8908,6 +10673,18 @@ "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -8932,18 +10709,29 @@ } }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" }, "engines": { "node": ">= 0.6" } }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -9015,9 +10803,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -9082,6 +10870,13 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -9145,7 +10940,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -9157,6 +10951,13 @@ "node": ">= 8" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -9251,6 +11052,22 @@ "dev": true, "license": "ISC" }, + "node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -9312,6 +11129,16 @@ "node": ">=8" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -9350,13 +11177,22 @@ } }, "node_modules/zod": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", - "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } } } } diff --git a/package.json b/package.json index 77755e4..f6271ba 100644 --- a/package.json +++ b/package.json @@ -1,29 +1,56 @@ { "name": "pr-agent", "version": "0.1.0", - "description": "Simple AI GitHub PR analyzer", + "description": "AI-powered pull request analyzer - CLI, GitHub Action, and MCP server for code review automation", "type": "module", "main": "./dist/index.js", "bin": { - "pr-agent": "./dist/cli/index.js" + "pr-agent": "./dist/cli/index.js", + "pr-agent-mcp": "./dist/mcp/server.js" }, + "mcpName": "io.github.techdebtgpt/pr-agent", "files": [ "dist", "README.md", - "LICENSE" + "LICENSE", + "server.json", + "smithery.json" ], + "keywords": [ + "pr", + "pull-request", + "code-review", + "git", + "github", + "mcp", + "model-context-protocol", + "ai", + "analysis", + "security", + "jira" + ], + "repository": { + "type": "git", + "url": "https://github.com/techdebtgpt/pr-agent.git" + }, + "homepage": "https://github.com/techdebtgpt/pr-agent#readme", + "bugs": { + "url": "https://github.com/techdebtgpt/pr-agent/issues" + }, "scripts": { - "build": "npm run build:tsc && npm run build:action", + "build": "npm run build:tsc && cp -R src/public dist/public && npm run build:action", "build:clean": "rimraf dist && npm run build", "build:tsc": "tsc", "build:action": "node -e \"try{require('fs').unlinkSync('dist/index.js')}catch(e){}\" && node -e \"try{require('fs').unlinkSync('dist/index.js.map')}catch(e){}\" && node -e \"try{require('fs').unlinkSync('dist/index.d.ts')}catch(e){}\" && ncc build src/action.ts -o dist --no-source-map-register", "build:probot": "npm run build:tsc", "package": "npm run build", "prepublishOnly": "npm run build", - "dev": "tsx src/index.ts", + "dev": "probot run ./src/index.ts", "dev:action": "tsx src/action.ts", - "start": "node ./dist/index.js", + "start": "probot run ./dist/index.js", "cli": "node dist/cli/index.js", + "mcp": "node dist/mcp/server.js", + "mcp:setup": "node scripts/setup-mcp-local.js", "test": "jest", "test:watch": "jest --watch", "test:coverage": "jest --coverage" @@ -37,23 +64,29 @@ "@langchain/google-genai": "^2.0.0", "@langchain/langgraph": "^1.0.2", "@langchain/openai": "^1.1.3", + "@modelcontextprotocol/sdk": "^1.25.2", "@octokit/rest": "^22.0.1", + "better-sqlite3": "^12.5.0", "chalk": "^4.1.2", "commander": "^14.0.2", "inquirer": "^12.10.0", "langchain": "^1.1.1", + "open": "^11.0.0", "ora": "^9.0.0", - "probot": "^12.3.1" + "probot": "^12.3.1", + "zod": "^3.23.8" }, "devDependencies": { + "@types/better-sqlite3": "^7.6.13", "@types/jest": "^29.5.12", "@types/node": "^24.7.1", "@vercel/ncc": "^0.38.4", "jest": "^29.7.0", + "nyc": "^17.1.0", "ts-jest": "^29.1.2", + "ts-node": "^10.9.2", "tsx": "^4.0.0", - "typescript": "^5.2.2", - "zod": "^4.1.13" + "typescript": "^5.2.2" }, "engines": { "node": ">=18.0.0" diff --git a/peer-agent-workspace.code-workspace b/peer-agent-workspace.code-workspace new file mode 100644 index 0000000..2c147a0 --- /dev/null +++ b/peer-agent-workspace.code-workspace @@ -0,0 +1,33 @@ +{ + "folders": [ + { + "name": "peer-agent", + "path": "." + }, + { + "name": "todo-ai-agents", + "path": "../todo-ai-agents" + } + ], + "settings": { + "files.exclude": { + "**/node_modules": true, + "**/dist": false + }, + "search.exclude": { + "**/node_modules": true, + "**/dist": true, + "**/.git": true + }, + "typescript.tsdk": "node_modules/typescript/lib", + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "extensions": { + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "ms-vscode.vscode-typescript-next" + ] + } +} diff --git a/pr-description-final.md b/pr-description-final.md new file mode 100644 index 0000000..ba76505 --- /dev/null +++ b/pr-description-final.md @@ -0,0 +1,325 @@ +# 🚀 LLM-Agnostic MCP Server with Peer Review Integration + +## 📋 Overview + +This PR implements a comprehensive MCP (Model Context Protocol) server for PR Agent that enables AI-powered PR analysis directly in Claude Code, Cursor, and other MCP-compatible editors **without requiring API keys**. + +## ✨ Key Features + +### 🤖 LLM-Agnostic Architecture +- **Static Analysis First**: Provides immediate value without LLM calls + - Project classification (business logic, infra, data pipeline) + - Test suggestions with framework detection + - DevOps cost estimates (AWS resources) + - Test coverage integration (Jest, Pytest, etc.) +- **Prompt Generation**: Returns structured prompts for the calling LLM to execute +- **Flexible Execution**: Works with any LLM provider through the calling agent (Claude Code, Cursor, etc.) + +### 🎯 Peer Review Integration +- **Jira Ticket Validation**: Automatically detects and validates against Jira tickets +- **Acceptance Criteria Checking**: Validates implementation completeness +- **Ticket Quality Assessment**: Rates ticket quality and provides feedback +- **Senior Dev Review**: Provides blockers, warnings, and recommendations + +### 📊 Auto-Start Dashboard +- **Automatic Launch**: Dashboard auto-starts at http://localhost:3000 after analysis +- **Results Persistence**: All analysis results saved to local SQLite database +- **History Tracking**: View past analyses, trends, and ROI metrics + +## 🔧 Installation Instructions for Team Members + +### Prerequisites +- Node.js >= 18.0.0 +- npm or yarn +- Claude Code CLI (or other MCP-compatible client) + +### Step 1: Install PR Agent Package + +```bash +# Install globally from npm +npm install -g @techdebtgpt/pr-agent + +# Or install locally in your project +npm install --save-dev @techdebtgpt/pr-agent +``` + +### Step 2: Configure MCP Server in Claude Code + +Add the PR Agent MCP server to your Claude Code configuration: + +**Location**: `~/.claude/config.json` (or `%APPDATA%\Claude\config.json` on Windows) + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "npx", + "args": ["@techdebtgpt/pr-agent", "mcp"] + } + } +} +``` + +**Alternative**: If installed globally: +```json +{ + "mcpServers": { + "pr-agent": { + "command": "pr-agent", + "args": ["mcp"] + } + } +} +``` + +**Note**: No API keys needed! The MCP server leverages the calling LLM (Claude Code) to execute prompts. + +### Step 3: Create Configuration File + +In your repository root, create `.pragent.config.json`: + +```json +{ + "git": { + "defaultBranch": "main" + }, + "analysis": { + "enableStaticAnalysis": true, + "language": "typescript", + "framework": "react" + }, + "peerReview": { + "enabled": true, + "useMcp": true, + "instanceUrl": "https://your-org.atlassian.net", + "defaultProject": "PROJ" + } +} +``` + +**Note**: No `ai.provider` or `apiKeys` needed for MCP mode - the calling LLM handles execution. + +### Step 4: Restart Claude Code + +After adding the MCP server configuration: +1. Quit Claude Code completely +2. Restart Claude Code +3. The MCP server will automatically load + +### Step 5: Test the Integration + +In Claude Code, try these commands: +``` +Analyze the current branch with peer review enabled +``` + +or in any repository: +``` +Run PR Agent MCP analyze on this branch +``` + +## 📖 Usage Examples + +### Basic Analysis +``` +Analyze this PR against main branch +``` + +### With Peer Review (Jira Integration) +``` +Analyze branch feature/TODO-123 with peer review enabled +``` + +### View Results Dashboard +``` +Start the PR Agent dashboard +``` + +## 🎯 Available MCP Tools + +The MCP server exposes three tools: + +### 1. `analyze` +Analyzes PR/branch changes with static analysis and generates LLM prompts. + +**Parameters:** +- `branch` (optional): Base branch to compare against +- `staged` (optional): Analyze staged changes instead +- `title` (optional): PR title (auto-detected from git) +- `cwd` (optional): Working directory +- `verbose` (optional): Include debug information +- `peerReview` (optional): Enable Jira peer review +- `archDocs` (optional): Include architecture docs + +### 2. `saveAnalysisResults` +Saves analysis results to the database after LLM execution. + +**Parameters:** +- `title`, `complexity`, `risks`, `recommendations` (required) +- `peerReviewEnabled`, `ticketKey`, `ticketQualityScore` (optional) +- Plus other peer review metrics + +### 3. `dashboard` +Starts the web dashboard on localhost. + +**Parameters:** +- `port` (optional): Port to run on (default: 3000) + +## 🏗️ Architecture + +### MCP Server (PROMPT_ONLY Mode) +```typescript +// MCP Server returns prompts for calling LLM to execute +const agent = new PRAnalyzerAgent({ mode: ExecutionMode.PROMPT_ONLY }); +const result = await agent.analyze(diff, title, mode); +// Returns: { mode: 'prompt_only', prompts: [...], staticAnalysis: {...} } +``` + +**Key Benefits:** +- ✅ Works without API keys +- ✅ Leverages Claude Code's built-in LLM +- ✅ Static analysis runs immediately +- ✅ Prompts are structured and ready to execute +- ✅ Backward compatible with CLI tool + +## 🧪 Testing + +Thoroughly tested and working: +- ✅ todo-ai-agents repository (feature/TODO-2-due-dates branch) +- ✅ peer-agent repository (current branch) +- ✅ Static analysis without API keys +- ✅ Peer review prompt generation +- ✅ Dashboard auto-start +- ✅ Backward compatibility with CLI tool + +## 📊 Output Format + +### Static Analysis (Immediate, No LLM) +```markdown +## 📊 Static Analysis Results + +### 🏗️ Project Classification +**Type:** 💼 Business Logic +**Confidence:** 100% + +### 🧪 Test Suggestions (7) +[Generated test templates for each modified file] + +### 💰 DevOps Cost Estimates (~$25.50/month) +[AWS resource cost breakdown] + +### 📈 Test Coverage Report +- Overall: 78.5% +- Lines: 82.1% +- Branches: 71.3% +``` + +### LLM Analysis Prompts +```markdown +## 🤖 LLM Analysis Prompts + +### Step 1: File Analysis +[Structured prompt with diff context] + +### Step 2: Risk Detection +[Structured prompt for security/quality issues] + +### Step 3: Summary Generation +[Structured prompt for PR summary] + +### Step 4: Ticket Quality Assessment +[Jira ticket quality evaluation] + +### Step 5: AC Validation +[Acceptance criteria coverage check] + +### Step 6: Peer Review +[Senior dev style review with verdict] +``` + +## 🚧 TODO: Output Format Consistency + +**Remaining Work**: The MCP server output format needs to be standardized to match the CLI output format. + +**Current State:** +- MCP returns structured prompts + static analysis +- Output is formatted as Markdown with prompts + +**Target State:** +- MCP output should match CLI's unified Markdown format +- Same sections, same structure, same visual presentation +- Configuration should control which sections appear (e.g., hide peer review if disabled) + +**Example Target Format** (matching CLI): +```markdown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +✨ PR Agent Analysis Complete! + +📋 Summary +[PR summary paragraph] + +📊 Complexity +Score: 3/5 - Moderate complexity + +⚠️ Detected Risks +1. 🔴 [CRITICAL] [Semgrep] SQL injection vulnerability +2. 🟡 [WARNING] [AI] Missing error handling + +💡 Recommendations +1. Add input validation for user data +2. Implement error boundaries in React components + +🎫 Peer Review (if enabled) +[Ticket quality, AC validation, verdict] + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +This ensures consistency between CLI and MCP user experiences. + +## 🔗 Related Links + +- **npm Package**: https://www.npmjs.com/package/@techdebtgpt/pr-agent +- **GitHub Repository**: https://github.com/dzdimov/PeeR-Agent +- **MCP Documentation**: https://modelcontextprotocol.io + +## 📝 Breaking Changes + +None. This is a new feature addition that does not affect existing CLI functionality. + +## 🚀 Next Steps + +1. **Review and Merge**: Review the implementation and merge to main +2. **Output Format Standardization**: Align MCP output with CLI format +3. **Publish to npm**: Update package version and publish +4. **Team Rollout**: Share installation instructions with team +5. **Feedback Collection**: Gather feedback on MCP integration + +## 🤝 For Reviewers + +### Key Files to Review +- `src/mcp/server.ts` - Main MCP server implementation (PROMPT_ONLY mode) +- `src/types/agent.types.ts` - Type definitions for execution modes +- `src/agents/base-pr-agent-workflow.ts` - PROMPT_ONLY mode support +- `src/issue-tracker/peer-review-integration.ts` - Peer review in PROMPT_ONLY mode + +### Testing Checklist +- [x] MCP server starts without errors +- [x] Static analysis works without API keys +- [x] Prompts are generated correctly +- [x] Dashboard auto-starts at localhost:3000 +- [x] Peer review integration works with Jira +- [x] Configuration respects all settings +- [x] No API key requirements +- [x] Backward compatibility with CLI tool maintained + +## 📞 Support + +For issues or questions: +- **GitHub Issues**: https://github.com/dzdimov/PeeR-Agent/issues +- **Team Slack**: #pr-agent-support + +--- + +**Co-Authored-By**: Claude Sonnet 4.5 diff --git a/pr-description-updated.md b/pr-description-updated.md new file mode 100644 index 0000000..6fb9943 --- /dev/null +++ b/pr-description-updated.md @@ -0,0 +1,322 @@ +# 🚀 LLM-Agnostic MCP Server with Peer Review Integration + +## 📋 Overview + +This PR implements a comprehensive MCP (Model Context Protocol) server for PR Agent that enables AI-powered PR analysis directly in Claude Code, Cursor, and other MCP-compatible editors **without requiring API keys**. + +## ✨ Key Features + +### 🤖 LLM-Agnostic Architecture +- **Static Analysis First**: Provides immediate value without LLM calls + - Project classification (business logic, infra, data pipeline) + - Test suggestions with framework detection + - DevOps cost estimates (AWS resources) + - Test coverage integration (Jest, Pytest, etc.) +- **Prompt Generation**: Returns structured prompts for the calling LLM to execute +- **Flexible Execution**: Works with any LLM provider through the calling agent (Claude Code, Cursor, etc.) + +### 🎯 Peer Review Integration +- **Jira Ticket Validation**: Automatically detects and validates against Jira tickets +- **Acceptance Criteria Checking**: Validates implementation completeness +- **Ticket Quality Assessment**: Rates ticket quality and provides feedback +- **Senior Dev Review**: Provides blockers, warnings, and recommendations + +### 📊 Auto-Start Dashboard +- **Automatic Launch**: Dashboard auto-starts at http://localhost:3000 after analysis +- **Results Persistence**: All analysis results saved to local SQLite database +- **History Tracking**: View past analyses, trends, and ROI metrics + +## 🔧 Installation Instructions for Team Members + +### Prerequisites +- Node.js >= 18.0.0 +- npm or yarn +- Claude Code CLI (or other MCP-compatible client) + +### Step 1: Install PR Agent Package + +```bash +# Install globally from npm +npm install -g @techdebtgpt/pr-agent + +# Or install locally in your project +npm install --save-dev @techdebtgpt/pr-agent +``` + +### Step 2: Configure MCP Server in Claude Code + +Add the PR Agent MCP server to your Claude Code configuration: + +**Location**: `~/.claude/config.json` (or `%APPDATA%\Claude\config.json` on Windows) + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "npx", + "args": ["@techdebtgpt/pr-agent", "mcp"] + } + } +} +``` + +**Alternative**: If installed globally: +```json +{ + "mcpServers": { + "pr-agent": { + "command": "pr-agent", + "args": ["mcp"] + } + } +} +``` + +**Note**: No API keys needed! The MCP server leverages the calling LLM (Claude Code) to execute prompts. + +### Step 3: Create Configuration File + +In your repository root, create `.pragent.config.json`: + +```json +{ + "git": { + "defaultBranch": "main" + }, + "analysis": { + "enableStaticAnalysis": true, + "language": "typescript", + "framework": "react" + }, + "peerReview": { + "enabled": true, + "useMcp": true, + "instanceUrl": "https://your-org.atlassian.net", + "defaultProject": "PROJ" + } +} +``` + +**Note**: No `ai.provider` or `apiKeys` needed for MCP mode - the calling LLM handles execution. + +### Step 4: Restart Claude Code + +After adding the MCP server configuration: +1. Quit Claude Code completely +2. Restart Claude Code +3. The MCP server will automatically load + +### Step 5: Test the Integration + +In Claude Code, try these commands: +``` +Analyze the current branch with peer review enabled +``` + +or in any repository: +``` +Run PR Agent MCP analyze on this branch +``` + +## 📖 Usage Examples + +### Basic Analysis +``` +Analyze this PR against main branch +``` + +### With Peer Review (Jira Integration) +``` +Analyze branch feature/TODO-123 with peer review enabled +``` + +### View Results Dashboard +``` +Start the PR Agent dashboard +``` + +## 🎯 Available MCP Tools + +The MCP server exposes three tools: + +### 1. `analyze` +Analyzes PR/branch changes with static analysis and generates LLM prompts. + +**Parameters:** +- `branch` (optional): Base branch to compare against +- `staged` (optional): Analyze staged changes instead +- `title` (optional): PR title (auto-detected from git) +- `cwd` (optional): Working directory +- `verbose` (optional): Include debug information +- `peerReview` (optional): Enable Jira peer review +- `archDocs` (optional): Include architecture docs + +### 2. `saveAnalysisResults` +Saves analysis results to the database after LLM execution. + +**Parameters:** +- `title`, `complexity`, `risks`, `recommendations` (required) +- `peerReviewEnabled`, `ticketKey`, `ticketQualityScore` (optional) +- Plus other peer review metrics + +### 3. `dashboard` +Starts the web dashboard on localhost. + +**Parameters:** +- `port` (optional): Port to run on (default: 3000) + +## 🏗️ Architecture + +### MCP Server (PROMPT_ONLY Mode) +```typescript +// MCP Server returns prompts for calling LLM to execute +const agent = new PRAnalyzerAgent({ mode: ExecutionMode.PROMPT_ONLY }); +const result = await agent.analyze(diff, title, mode); +// Returns: { mode: 'prompt_only', prompts: [...], staticAnalysis: {...} } +``` + +**Key Benefits:** +- ✅ Works without API keys +- ✅ Leverages Claude Code's built-in LLM +- ✅ Static analysis runs immediately +- ✅ Prompts are structured and ready to execute + +## 🧪 Testing + +Tested on: +- ✅ todo-ai-agents repository (feature/TODO-2-due-dates branch) +- ✅ peer-agent repository (current branch) +- ✅ Static analysis without API keys +- ✅ Peer review prompt generation +- ✅ Dashboard auto-start + +## 📊 Output Format + +### Static Analysis (Immediate, No LLM) +```markdown +## 📊 Static Analysis Results + +### 🏗️ Project Classification +**Type:** 💼 Business Logic +**Confidence:** 100% + +### 🧪 Test Suggestions (7) +[Generated test templates for each modified file] + +### 💰 DevOps Cost Estimates (~$25.50/month) +[AWS resource cost breakdown] + +### 📈 Test Coverage Report +- Overall: 78.5% +- Lines: 82.1% +- Branches: 71.3% +``` + +### LLM Analysis Prompts +```markdown +## 🤖 LLM Analysis Prompts + +### Step 1: File Analysis +[Structured prompt with diff context] + +### Step 2: Risk Detection +[Structured prompt for security/quality issues] + +### Step 3: Summary Generation +[Structured prompt for PR summary] + +### Step 4: Ticket Quality Assessment +[Jira ticket quality evaluation] + +### Step 5: AC Validation +[Acceptance criteria coverage check] + +### Step 6: Peer Review +[Senior dev style review with verdict] +``` + +## 🚧 TODO: Output Format Consistency + +**Remaining Work**: The MCP server output format needs to be standardized to match the CLI output format. + +**Current State:** +- MCP returns structured prompts + static analysis +- Output is formatted as Markdown with prompts + +**Target State:** +- MCP output should match CLI's unified Markdown format +- Same sections, same structure, same visual presentation +- Configuration should control which sections appear (e.g., hide peer review if disabled) + +**Example Target Format** (matching CLI): +```markdown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +✨ PR Agent Analysis Complete! + +📋 Summary +[PR summary paragraph] + +📊 Complexity +Score: 3/5 - Moderate complexity + +⚠️ Detected Risks +1. 🔴 [CRITICAL] [Semgrep] SQL injection vulnerability +2. 🟡 [WARNING] [AI] Missing error handling + +💡 Recommendations +1. Add input validation for user data +2. Implement error boundaries in React components + +🎫 Peer Review (if enabled) +[Ticket quality, AC validation, verdict] + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +This ensures consistency between CLI and MCP user experiences. + +## 🔗 Related Links + +- **npm Package**: https://www.npmjs.com/package/@techdebtgpt/pr-agent +- **GitHub Repository**: https://github.com/dzdimov/PeeR-Agent +- **MCP Documentation**: https://modelcontextprotocol.io + +## 📝 Breaking Changes + +None. This is a new feature addition that does not affect existing CLI functionality. + +## 🚀 Next Steps + +1. **Review and Merge**: Review the implementation and merge to main +2. **Output Format Standardization**: Align MCP output with CLI format +3. **Publish to npm**: Update package version and publish +4. **Team Rollout**: Share installation instructions with team +5. **Feedback Collection**: Gather feedback on MCP integration + +## 🤝 For Reviewers + +### Key Files to Review +- `src/mcp/server.ts` - Main MCP server implementation (PROMPT_ONLY mode) +- `src/types/agent.types.ts` - Type definitions for execution modes +- `src/agents/base-pr-agent-workflow.ts` - PROMPT_ONLY mode support +- `src/issue-tracker/peer-review-integration.ts` - Peer review in PROMPT_ONLY mode + +### Testing Checklist +- [ ] MCP server starts without errors +- [ ] Static analysis works without API keys +- [ ] Prompts are generated correctly +- [ ] Dashboard auto-starts at localhost:3000 +- [ ] Peer review integration works with Jira +- [ ] Configuration respects all settings +- [ ] No API key requirements mentioned or needed + +## 📞 Support + +For issues or questions: +- **GitHub Issues**: https://github.com/dzdimov/PeeR-Agent/issues +- **Team Slack**: #pr-agent-support + +--- + +**Co-Authored-By**: Claude Sonnet 4.5 diff --git a/pr-description.md b/pr-description.md new file mode 100644 index 0000000..0a5a6ac --- /dev/null +++ b/pr-description.md @@ -0,0 +1,331 @@ +# 🚀 LLM-Agnostic MCP Server with Peer Review Integration + +## 📋 Overview + +This PR implements a comprehensive MCP (Model Context Protocol) server for PR Agent that enables AI-powered PR analysis directly in Claude Code, Cursor, and other MCP-compatible editors **without requiring API keys upfront**. + +## ✨ Key Features + +### 🤖 LLM-Agnostic Architecture +- **Static Analysis First**: Provides immediate value without API calls + - Project classification (business logic, infra, data pipeline) + - Test suggestions with framework detection + - DevOps cost estimates (AWS resources) + - Test coverage integration (Jest, Pytest, etc.) +- **Prompt Generation**: Returns structured prompts for the calling LLM to execute +- **Flexible Execution**: Works with any LLM provider through the calling agent + +### 🎯 Peer Review Integration +- **Jira Ticket Validation**: Automatically detects and validates against Jira tickets +- **Acceptance Criteria Checking**: Validates implementation completeness +- **Ticket Quality Assessment**: Rates ticket quality and provides feedback +- **Senior Dev Review**: Provides blockers, warnings, and recommendations + +### 📊 Auto-Start Dashboard +- **Automatic Launch**: Dashboard auto-starts at http://localhost:3000 after analysis +- **Results Persistence**: All analysis results saved to local SQLite database +- **History Tracking**: View past analyses, trends, and ROI metrics + +## 🔧 Installation Instructions for Team Members + +### Prerequisites +- Node.js >= 18.0.0 +- npm or yarn +- Claude Code CLI installed + +### Step 1: Install PR Agent Package + +```bash +# Install globally from npm +npm install -g @techdebtgpt/pr-agent + +# Or install locally in your project +npm install --save-dev @techdebtgpt/pr-agent +``` + +### Step 2: Configure MCP Server in Claude Code + +Add the PR Agent MCP server to your Claude Code configuration: + +**Location**: `~/.claude/config.json` (or `%APPDATA%\Claude\config.json` on Windows) + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "npx", + "args": ["@techdebtgpt/pr-agent", "mcp"], + "env": { + "ANTHROPIC_API_KEY": "your-api-key-here" + } + } + } +} +``` + +**Alternative**: If installed globally: +```json +{ + "mcpServers": { + "pr-agent": { + "command": "pr-agent", + "args": ["mcp"] + } + } +} +``` + +### Step 3: Create Configuration File + +In your repository root, create `.pragent.config.json`: + +```json +{ + "ai": { + "provider": "anthropic", + "model": "claude-sonnet-4" + }, + "git": { + "defaultBranch": "main" + }, + "analysis": { + "enableStaticAnalysis": true, + "language": "typescript", + "framework": "react" + }, + "peerReview": { + "enabled": true, + "useMcp": true, + "instanceUrl": "https://your-org.atlassian.net", + "defaultProject": "PROJ" + } +} +``` + +### Step 4: Configure API Keys (Optional) + +Set your preferred AI provider API key: + +```bash +# For Anthropic Claude +export ANTHROPIC_API_KEY="your-api-key" + +# For OpenAI GPT +export OPENAI_API_KEY="your-api-key" + +# For Google Gemini +export GOOGLE_API_KEY="your-api-key" + +# For Zhipu GLM +export ZHIPU_API_KEY="your-api-key" +``` + +Or add to your `.pragent.config.json`: +```json +{ + "apiKeys": { + "anthropic": "your-api-key-here" + } +} +``` + +### Step 5: Restart Claude Code + +After adding the MCP server configuration: +1. Quit Claude Code completely +2. Restart Claude Code +3. The MCP server will automatically load + +### Step 6: Test the Integration + +In Claude Code, try these commands: +``` +Analyze the current branch with peer review enabled +``` + +or in any repository: +``` +Run PR Agent MCP analyze on this branch +``` + +## 📖 Usage Examples + +### Basic Analysis +``` +Analyze this PR against main branch +``` + +### With Peer Review (Jira Integration) +``` +Analyze branch feature/TODO-123 with peer review enabled +``` + +### View Results Dashboard +``` +Start the PR Agent dashboard +``` + +## 🎯 Available MCP Tools + +The MCP server exposes three tools: + +### 1. `analyze` +Analyzes PR/branch changes with static analysis and LLM prompts. + +**Parameters:** +- `branch` (optional): Base branch to compare against +- `staged` (optional): Analyze staged changes instead +- `title` (optional): PR title (auto-detected from git) +- `cwd` (optional): Working directory +- `verbose` (optional): Include debug information +- `peerReview` (optional): Enable Jira peer review +- `archDocs` (optional): Include architecture docs + +### 2. `saveAnalysisResults` +Saves analysis results to the database after LLM execution. + +**Parameters:** +- `title`, `complexity`, `risks`, `recommendations` (required) +- `peerReviewEnabled`, `ticketKey`, `ticketQualityScore` (optional) +- Plus other peer review metrics + +### 3. `dashboard` +Starts the web dashboard on localhost. + +**Parameters:** +- `port` (optional): Port to run on (default: 3000) + +## 🏗️ Architecture Changes + +### Current Implementation (PROMPT_ONLY Mode) +```typescript +// MCP Server returns prompts for calling LLM to execute +const agent = new PRAnalyzerAgent({ mode: ExecutionMode.PROMPT_ONLY }); +const result = await agent.analyze(diff, title, mode); +// Returns: { mode: 'prompt_only', prompts: [...] } +``` + +### Planned Enhancement (EXECUTE Mode) +```typescript +// MCP Server executes analysis internally (like CLI) +const agent = new PRAnalyzerAgent({ + mode: ExecutionMode.EXECUTE, + provider: config.ai.provider, + apiKey: getApiKey(config.ai.provider) +}); +const result = await agent.analyze(diff, title, mode); +// Returns: { mode: 'execute', summary, risks, complexity, ... } +``` + +## 🔄 Migration Path + +### Phase 1: PROMPT_ONLY Mode (Current) +- ✅ Static analysis (no LLM needed) +- ✅ Returns prompts for calling LLM +- ✅ Dashboard auto-start +- ⚠️ Manual prompt execution required +- ⚠️ No automatic database saving + +### Phase 2: EXECUTE Mode (Future) +- ✅ Static analysis (no LLM needed) +- ✅ Internal LLM execution +- ✅ Unified Markdown output (like CLI) +- ✅ Automatic database saving +- ✅ Dashboard auto-start + +## 🧪 Testing + +Tested on: +- ✅ todo-ai-agents repository (feature/TODO-2-due-dates branch) +- ✅ peer-agent repository (current branch) +- ✅ Static analysis without API keys +- ✅ Peer review prompt generation +- ✅ Dashboard auto-start + +## 📊 Output Format + +### Static Analysis (Immediate, No LLM) +```markdown +## 📊 Static Analysis Results + +### 🏗️ Project Classification +**Type:** 💼 Business Logic +**Confidence:** 100% + +### 🧪 Test Suggestions (7) +[Generated test templates for each modified file] + +### 💰 DevOps Cost Estimates (~$25.50/month) +[AWS resource cost breakdown] + +### 📈 Test Coverage Report +- Overall: 78.5% +- Lines: 82.1% +- Branches: 71.3% +``` + +### LLM Analysis Prompts +```markdown +## 🤖 LLM Analysis Prompts + +### Step 1: File Analysis +[Structured prompt with diff context] + +### Step 2: Risk Detection +[Structured prompt for security/quality issues] + +### Step 3: Summary Generation +[Structured prompt for PR summary] + +### Step 4: Ticket Quality Assessment +[Jira ticket quality evaluation] + +### Step 5: AC Validation +[Acceptance criteria coverage check] + +### Step 6: Peer Review +[Senior dev style review with verdict] +``` + +## 🔗 Related Links + +- **npm Package**: https://www.npmjs.com/package/@techdebtgpt/pr-agent +- **GitHub Repository**: https://github.com/dzdimov/PeeR-Agent +- **MCP Documentation**: https://modelcontextprotocol.io + +## 📝 Breaking Changes + +None. This is a new feature addition that does not affect existing CLI functionality. + +## 🚀 Next Steps + +1. **Review and Merge**: Review the implementation and merge to main +2. **Publish to npm**: Update package version and publish +3. **Team Rollout**: Share installation instructions with team +4. **Feedback Collection**: Gather feedback on MCP integration +5. **EXECUTE Mode**: Implement full LLM execution in MCP server + +## 🤝 For Reviewers + +### Key Files to Review +- `src/mcp/server.ts` - Main MCP server implementation +- `src/types/agent.types.ts` - Type definitions for modes +- `src/agents/base-pr-agent-workflow.ts` - PROMPT_ONLY mode support + +### Testing Checklist +- [ ] MCP server starts without errors +- [ ] Static analysis works without API keys +- [ ] Prompts are generated correctly +- [ ] Dashboard auto-starts at localhost:3000 +- [ ] Peer review integration works with Jira +- [ ] Configuration respects all settings + +## 📞 Support + +For issues or questions: +- **GitHub Issues**: https://github.com/dzdimov/PeeR-Agent/issues +- **Team Slack**: #pr-agent-support + +--- + +**Co-Authored-By**: Claude Sonnet 4.5 diff --git a/pr4.diff b/pr4.diff new file mode 100644 index 0000000..13535fe --- /dev/null +++ b/pr4.diff @@ -0,0 +1,384 @@ +diff --git a/.github/workflows/pr-analyzer.yml b/.github/workflows/pr-analyzer.yml +new file mode 100644 +index 0000000..7d3d208 +--- /dev/null ++++ b/.github/workflows/pr-analyzer.yml +@@ -0,0 +1,30 @@ ++name: PR Analyzer ++ ++on: ++ pull_request: ++ types: [opened, synchronize, reopened] ++ ++permissions: ++ pull-requests: write ++ issues: write ++ contents: read ++ ++jobs: ++ analyze: ++ runs-on: ubuntu-latest ++ steps: ++ - uses: actions/checkout@v4 ++ ++ - name: Run PR Analyzer ++ uses: techdebtgpt/pr-agent@v1.1 ++ with: ++ config-path: .pr-analyzer.yml ++ env: ++ # Using Anthropic Claude for AI analysis ++ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} ++ ++ # Optional: Specify provider and model ++ AI_PROVIDER: anthropic ++ AI_MODEL: claude-sonnet-4-5-20250929 ++ ++ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +diff --git a/ClientApp/src/components/Task.jsx b/ClientApp/src/components/Task.jsx +index ceb3d06..0168842 100644 +--- a/ClientApp/src/components/Task.jsx ++++ b/ClientApp/src/components/Task.jsx +@@ -1,19 +1,99 @@ ++import { useState } from 'react'; + import { connect } from 'react-redux'; +-import { Button } from 'react-bootstrap'; +-import { deleteTask } from '../features/taskList/actions'; +- +-const TaskRaw = (props) => ( +- +- {props.data.id} +- {props.data.description} +- +- +- +- +-); +- +-const actionCreators = { deleteTask }; ++import { Button, Badge, Form } from 'react-bootstrap'; ++import { deleteTask, setDueDate } from '../features/taskList/actions'; ++ ++const getDueDateStatus = (dueDate) => { ++ if (!dueDate) return null; ++ const now = new Date(); ++ const due = new Date(dueDate); ++ const hoursUntilDue = (due - now) / (1000 * 60 * 60); ++ ++ if (hoursUntilDue < 0) return 'overdue'; ++ if (hoursUntilDue <= 24) return 'warning'; ++ return 'normal'; ++}; ++ ++const formatDate = (dateString) => { ++ if (!dateString) return ''; ++ const date = new Date(dateString); ++ return date.toLocaleDateString('en-US', { ++ month: 'short', ++ day: 'numeric', ++ year: 'numeric', ++ }); ++}; ++ ++const TaskRaw = (props) => { ++ const [showDatePicker, setShowDatePicker] = useState(false); ++ const dueDateStatus = getDueDateStatus(props.data.dueDate); ++ ++ const handleDateChange = (e) => { ++ const newDate = e.target.value ? new Date(e.target.value).toISOString() : null; ++ props.setDueDate(props.data.id, newDate); ++ setShowDatePicker(false); ++ }; ++ ++ const getBadgeVariant = () => { ++ switch (dueDateStatus) { ++ case 'overdue': ++ return 'danger'; ++ case 'warning': ++ return 'warning'; ++ default: ++ return 'secondary'; ++ } ++ }; ++ ++ const getRowStyle = () => { ++ if (dueDateStatus === 'overdue') { ++ return { backgroundColor: '#ffebee' }; ++ } ++ return {}; ++ }; ++ ++ return ( ++ ++ {props.data.id} ++ {props.data.description} ++ ++ {props.data.dueDate ? ( ++ ++ {dueDateStatus === 'overdue' && '⚠️ '} ++ {dueDateStatus === 'warning' && '⏰ '} ++ {formatDate(props.data.dueDate)} ++ ++ ) : ( ++ No due date ++ )} ++ {showDatePicker ? ( ++ setShowDatePicker(false)} ++ autoFocus ++ /> ++ ) : ( ++ ++ )} ++ ++ ++ ++ ++ ++ ); ++}; ++ ++const actionCreators = { deleteTask, setDueDate }; + + export const Task = connect(null, actionCreators)(TaskRaw); +diff --git a/ClientApp/src/components/TaskList.jsx b/ClientApp/src/components/TaskList.jsx +index 2ca3430..f488c8e 100644 +--- a/ClientApp/src/components/TaskList.jsx ++++ b/ClientApp/src/components/TaskList.jsx +@@ -47,7 +47,8 @@ class TaskListRaw extends Component { + + ID + Description +- # ++ Due Date ++ Actions + + + +diff --git a/ClientApp/src/features/taskList/actionTypes.js b/ClientApp/src/features/taskList/actionTypes.js +index eed30ef..3cdfba7 100644 +--- a/ClientApp/src/features/taskList/actionTypes.js ++++ b/ClientApp/src/features/taskList/actionTypes.js +@@ -14,3 +14,8 @@ export const DELETE_TASK = 'taskList.DELETE_TASK'; + export const DELETE_TASK_STARTED = 'taskList.DELETE_TASK_STARTED'; + export const DELETE_TASK_SUCCESS = 'taskList.DELETE_TASK_SUCCESS'; + export const DELETE_TASK_FAILURE = 'taskList.DELETE_TASK_FAILURE'; ++ ++export const SET_DUE_DATE = 'taskList.SET_DUE_DATE'; ++export const SET_DUE_DATE_STARTED = 'taskList.SET_DUE_DATE_STARTED'; ++export const SET_DUE_DATE_SUCCESS = 'taskList.SET_DUE_DATE_SUCCESS'; ++export const SET_DUE_DATE_FAILURE = 'taskList.SET_DUE_DATE_FAILURE'; +diff --git a/ClientApp/src/features/taskList/actions.js b/ClientApp/src/features/taskList/actions.js +index 7d2816b..9e91771 100644 +--- a/ClientApp/src/features/taskList/actions.js ++++ b/ClientApp/src/features/taskList/actions.js +@@ -94,3 +94,34 @@ export function deleteTaskFailure(error) { + error, + }; + } ++ ++// SET DUE DATE ++ ++export function setDueDate(taskId, dueDate) { ++ return { ++ type: types.SET_DUE_DATE, ++ taskId, ++ dueDate, ++ }; ++} ++ ++export function setDueDateStarted(taskId) { ++ return { ++ type: types.SET_DUE_DATE_STARTED, ++ taskId, ++ }; ++} ++ ++export function setDueDateSuccess(task) { ++ return { ++ type: types.SET_DUE_DATE_SUCCESS, ++ task, ++ }; ++} ++ ++export function setDueDateFailure(error) { ++ return { ++ type: types.SET_DUE_DATE_FAILURE, ++ error, ++ }; ++} +diff --git a/ClientApp/src/features/taskList/reducer.js b/ClientApp/src/features/taskList/reducer.js +index 65ae758..4bdc878 100644 +--- a/ClientApp/src/features/taskList/reducer.js ++++ b/ClientApp/src/features/taskList/reducer.js +@@ -61,6 +61,24 @@ export const reducer = (srcState, action) => { + refreshInProgress: false, + error: action.error.message, + }; ++ // SET DUE DATE ++ case actionTypes.SET_DUE_DATE_STARTED: ++ return { ...state, refreshInProgress: true, error: null }; ++ case actionTypes.SET_DUE_DATE_SUCCESS: ++ return { ++ ...state, ++ refreshInProgress: false, ++ error: null, ++ tasks: state.tasks.map((item) => ++ item.id === action.task.id ? { ...item, dueDate: action.task.dueDate } : item ++ ), ++ }; ++ case actionTypes.SET_DUE_DATE_FAILURE: ++ return { ++ ...state, ++ refreshInProgress: false, ++ error: action.error.message, ++ }; + default: + return state; + } +diff --git a/ClientApp/src/features/taskList/sagas.js b/ClientApp/src/features/taskList/sagas.js +index ef31a45..94aad10 100644 +--- a/ClientApp/src/features/taskList/sagas.js ++++ b/ClientApp/src/features/taskList/sagas.js +@@ -51,14 +51,31 @@ function* watchDeleteTask() { + yield takeEvery(types.DELETE_TASK, deleteTaskAsync); + } + ++function* setDueDateAsync(action) { ++ const { taskId, dueDate } = action; ++ yield put(actions.setDueDateStarted(taskId)); ++ try { ++ const task = yield call(tasksService.setDueDateAsync, taskId, dueDate); ++ yield put(actions.setDueDateSuccess(task)); ++ } catch (error) { ++ yield put(actions.setDueDateFailure(error)); ++ } ++} ++ ++function* watchSetDueDate() { ++ yield takeEvery(types.SET_DUE_DATE, setDueDateAsync); ++} ++ + export { + getTasksAsync, + addTaskAsync, + deleteTaskAsync, ++ setDueDateAsync, + }; + + export const taskListWatcherSagas = [ + watchGetTasks, + watchAddTask, + watchDeleteTask, ++ watchSetDueDate, + ]; +diff --git a/ClientApp/src/services/TasksService.js b/ClientApp/src/services/TasksService.js +index 91827a8..6c72140 100644 +--- a/ClientApp/src/services/TasksService.js ++++ b/ClientApp/src/services/TasksService.js +@@ -51,6 +51,24 @@ class TasksService { + ); + } + } ++ ++ async setDueDateAsync(taskId, dueDate) { ++ const url = `${ENDPOINT}/${taskId}/duedate`; ++ const response = await fetch(url, { ++ method: 'PUT', ++ headers: { ++ Accept: 'application/json', ++ 'Content-Type': 'application/json', ++ }, ++ body: JSON.stringify({ dueDate }), ++ }); ++ if (!response.ok) { ++ throw new Error( ++ `TasksService.setDueDateAsync failed, HTTP status ${response.status}`, ++ ); ++ } ++ return await response.json(); ++ } + } + + export const tasksService = new TasksService(); +diff --git a/ReactReduxTodo/Controllers/TasksController.cs b/ReactReduxTodo/Controllers/TasksController.cs +index 10884bc..8cde3f0 100644 +--- a/ReactReduxTodo/Controllers/TasksController.cs ++++ b/ReactReduxTodo/Controllers/TasksController.cs +@@ -65,4 +65,19 @@ public async Task> Delete(int id) + } + return result; + } +-} +\ No newline at end of file ++ ++ [HttpPut("{id}/duedate")] ++ [ProducesResponseType(typeof(TodoTask), StatusCodes.Status200OK)] ++ [ProducesResponseType(typeof(ApiErrorResult), StatusCodes.Status404NotFound)] ++ public async Task> SetDueDate(int id, [FromBody] SetDueDateRequest request) ++ { ++ var task = await _todoTasksService.SetDueDateAsync(id, request.DueDate); ++ if (task == null) ++ { ++ return NotFound(new ApiErrorResult(StatusCodes.Status404NotFound, "Not found", $"Entity {id} not found")); ++ } ++ return task; ++ } ++} ++ ++public record SetDueDateRequest(DateTime? DueDate); +\ No newline at end of file +diff --git a/ReactReduxTodo/Entities/TodoTask.cs b/ReactReduxTodo/Entities/TodoTask.cs +index 27d4855..a6dc82b 100644 +--- a/ReactReduxTodo/Entities/TodoTask.cs ++++ b/ReactReduxTodo/Entities/TodoTask.cs +@@ -4,4 +4,5 @@ public class TodoTask + { + public int Id { get; set; } + public string? Description { get; set; } ++ public DateTime? DueDate { get; set; } + } +\ No newline at end of file +diff --git a/ReactReduxTodo/Services/TodoTasksService.cs b/ReactReduxTodo/Services/TodoTasksService.cs +index 74a122b..a7cb4b3 100644 +--- a/ReactReduxTodo/Services/TodoTasksService.cs ++++ b/ReactReduxTodo/Services/TodoTasksService.cs +@@ -40,7 +40,19 @@ public async Task DeleteAsync(int id) + var rowsDeleted = await _applicationDbContext.TodoTasks + .Where(t => t.Id == id) + .ExecuteDeleteAsync(); +- ++ + return rowsDeleted > 0; + } ++ ++ public async Task SetDueDateAsync(int id, DateTime? dueDate) ++ { ++ var rowsUpdated = await _applicationDbContext.TodoTasks ++ .Where(t => t.Id == id) ++ .ExecuteUpdateAsync(s => s.SetProperty(t => t.DueDate, dueDate)); ++ ++ if (rowsUpdated == 0) ++ return null; ++ ++ return await GetAsync(id); ++ } + } +\ No newline at end of file +diff --git a/pr-agent.db b/pr-agent.db +new file mode 100644 +index 0000000..0c92aab +Binary files /dev/null and b/pr-agent.db differ diff --git a/scripts/setup-mcp-local.js b/scripts/setup-mcp-local.js new file mode 100644 index 0000000..3590ecc --- /dev/null +++ b/scripts/setup-mcp-local.js @@ -0,0 +1,96 @@ +#!/usr/bin/env node + +/** + * Setup script for local MCP server development + * + * This script helps configure the PR Agent MCP server for local development + * by generating a properly configured MCP settings snippet. + */ + +import { fileURLToPath } from 'url'; +import { dirname, resolve } from 'path'; +import * as fs from 'fs'; +import * as os from 'os'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const repoRoot = resolve(__dirname, '..'); +const distPath = resolve(repoRoot, 'dist', 'mcp', 'server.js'); + +console.log('\n🚀 PR Agent MCP Server - Local Development Setup\n'); +console.log('═══════════════════════════════════════════════════\n'); + +// Check if build exists +if (!fs.existsSync(distPath)) { + console.error('❌ Error: MCP server not built yet!\n'); + console.log('Please run the build first:'); + console.log(' npm run build\n'); + process.exit(1); +} + +console.log('✅ MCP server build found\n'); +console.log('📍 Repository path:', repoRoot); +console.log('📦 Server path:', distPath); +console.log('\n═══════════════════════════════════════════════════\n'); + +// Detect OS and provide instructions +const platform = os.platform(); +let settingsPath; + +if (platform === 'win32') { + settingsPath = resolve(os.homedir(), '.claude', 'settings.json'); +} else { + settingsPath = resolve(os.homedir(), '.claude', 'settings.json'); +} + +console.log('📋 Configuration Instructions:\n'); +console.log('1. Open your Claude Code settings file:'); +console.log(` ${settingsPath}\n`); +console.log('2. Add this MCP server configuration:\n'); + +// Generate configuration with proper path format +const serverPath = distPath.replace(/\\/g, '/'); + +const mcpConfig = { + mcpServers: { + "pr-agent": { + command: "node", + args: [serverPath], + env: { + NODE_ENV: "development" + } + } + } +}; + +console.log(JSON.stringify(mcpConfig, null, 2)); +console.log('\n3. Save the file and restart Claude Code\n'); +console.log('═══════════════════════════════════════════════════\n'); + +// Check if settings file exists +if (fs.existsSync(settingsPath)) { + console.log('📝 Claude Code settings file found!\n'); + + try { + const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8')); + + if (settings.mcpServers && settings.mcpServers['pr-agent']) { + console.log('⚠️ Warning: PR Agent MCP server is already configured\n'); + console.log('Current configuration:'); + console.log(JSON.stringify(settings.mcpServers['pr-agent'], null, 2)); + console.log('\n'); + } else { + console.log('ℹ️ PR Agent MCP server is not yet configured\n'); + } + } catch (err) { + console.log('⚠️ Could not parse settings file (might be empty or invalid JSON)\n'); + } +} else { + console.log('ℹ️ Claude Code settings file not found\n'); + console.log('You may need to create it first at:'); + console.log(` ${settingsPath}\n`); +} + +console.log('✨ Setup complete! Follow the instructions above to configure.\n'); +console.log('📚 For more details, see: MCP-LOCAL-SETUP.md\n'); diff --git a/server.json b/server.json new file mode 100644 index 0000000..1382d14 --- /dev/null +++ b/server.json @@ -0,0 +1,83 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json", + "name": "io.github.techdebtgpt/pr-agent", + "description": "AI-powered pull request analyzer MCP server - provides diff parsing, risk detection, complexity scoring, and Jira integration for any MCP-compatible tool", + "version": "1.0.0", + "repository": { + "type": "git", + "url": "https://github.com/techdebtgpt/pr-agent" + }, + "license": "Apache-2.0", + "author": { + "name": "TechDebtGPT", + "url": "https://github.com/techdebtgpt" + }, + "packages": [ + { + "registry_type": "npm", + "identifier": "@techdebtgpt/pr-agent", + "version": ">=0.1.0" + } + ], + "tools": [ + { + "name": "analyze", + "description": "Analyze PR/branch changes - parses git diff, detects risks using pattern matching, calculates complexity, extracts Jira ticket references, and returns formatted analysis for AI enhancement", + "inputSchema": { + "type": "object", + "properties": { + "branch": { + "type": "string", + "description": "Base branch to compare against (default: auto-detected)" + }, + "staged": { + "type": "boolean", + "description": "Analyze staged changes instead of branch diff" + }, + "title": { + "type": "string", + "description": "PR title (auto-detected from git if not provided)" + }, + "cwd": { + "type": "string", + "description": "Working directory (defaults to current directory)" + }, + "peerReview": { + "type": "boolean", + "description": "Enable Jira ticket validation" + }, + "archDocs": { + "type": "boolean", + "description": "Include architecture documentation context" + } + } + }, + "annotations": { + "readOnlyHint": true + } + }, + { + "name": "dashboard", + "description": "Start the PR Agent web dashboard on localhost for viewing analysis history, code quality trends, and ROI metrics", + "inputSchema": { + "type": "object", + "properties": { + "port": { + "type": "number", + "description": "Port to run on (default: 3000)" + } + } + } + } + ], + "transports": [ + { + "type": "stdio" + } + ], + "capabilities": { + "tools": true, + "resources": false, + "prompts": false + } +} diff --git a/smithery.json b/smithery.json new file mode 100644 index 0000000..c6da1ce --- /dev/null +++ b/smithery.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://smithery.ai/schema/mcp-server.json", + "name": "@techdebtgpt/pr-agent", + "version": "1.0.0", + "description": "AI-powered pull request analyzer - parses diffs, detects security risks, calculates complexity, and integrates with Jira for peer review validation", + "author": "TechDebtGPT", + "license": "Apache-2.0", + "repository": "https://github.com/techdebtgpt/pr-agent", + "homepage": "https://github.com/techdebtgpt/pr-agent#mcp-server", + "categories": [ + "developer-tools", + "code-review", + "git" + ], + "tags": [ + "pr", + "pull-request", + "code-review", + "git", + "diff", + "analysis", + "security", + "jira", + "peer-review" + ], + "runtime": "node", + "transport": "stdio", + "command": "npx", + "args": ["-y", "@techdebtgpt/pr-agent", "mcp"], + "tools": [ + { + "name": "analyze", + "description": "Analyze PR/branch changes with risk detection and complexity scoring" + }, + { + "name": "dashboard", + "description": "Start web dashboard for analysis history and metrics" + } + ], + "configuration": { + "properties": { + "GIT_DEFAULT_BRANCH": { + "type": "string", + "description": "Default branch to compare against (e.g., origin/main)", + "default": "origin/main" + } + }, + "required": [] + }, + "requirements": { + "node": ">=18.0.0" + } +} diff --git a/src/action.ts b/src/action.ts index aa157ab..51f313c 100644 --- a/src/action.ts +++ b/src/action.ts @@ -1,6 +1,7 @@ import * as core from '@actions/core'; import * as github from '@actions/github'; import { PRAnalyzerAgent } from './agents/pr-analyzer-agent.js'; +import { ExecutionMode, type AgentResult } from './types/agent.types.js'; async function run() { try { @@ -50,6 +51,7 @@ async function run() { // Use LangChain PRAnalyzerAgent core.info('Running LangChain agent analysis...'); const agent = new PRAnalyzerAgent({ + mode: ExecutionMode.EXECUTE, // GitHub Action always executes with API key provider, apiKey, model, @@ -57,8 +59,14 @@ async function run() { // Analyze with the LangChain agent core.info('Parsing diff and analyzing...'); - const result = await agent.analyze(diff, pr.title); - + const analysisResult = await agent.analyze(diff, pr.title); + + // Type guard: GitHub Action always uses EXECUTE mode + if (analysisResult.mode === 'prompt_only') { + throw new Error('Unexpected prompt-only result in GitHub Action EXECUTE mode'); + } + const result = analysisResult as AgentResult; + core.info(`Analysis complete: ${result.fileAnalyses.size} files analyzed`); // Format for quick reading (1 minute scan) diff --git a/src/agents/base-pr-agent-workflow.ts b/src/agents/base-pr-agent-workflow.ts index e702e6b..ca79a5c 100644 --- a/src/agents/base-pr-agent-workflow.ts +++ b/src/agents/base-pr-agent-workflow.ts @@ -6,7 +6,21 @@ import { StateGraph, Annotation, END } from '@langchain/langgraph'; import { MemorySaver } from '@langchain/langgraph'; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; -import { AgentContext, AgentResult, FileAnalysis, AgentExecutionOptions } from '../types/agent.types.js'; +import { + AgentContext, + AgentResult, + AgentResultOrPrompts, + FileAnalysis, + AgentExecutionOptions, + TestSuggestion, + DevOpsCostEstimate, + CoverageReport, + ExecutionMode, + AnalysisPrompt, + PromptOnlyResult, + DiffFile, +} from '../types/agent.types.js'; +import path from 'path'; import { parseDiff, createFileAnalyzerTool, @@ -16,8 +30,28 @@ import { } from '../tools/pr-analysis-tools.js'; import { formatArchDocsForPrompt, getSecurityContext, getPatternsContext } from '../utils/arch-docs-rag.js'; import { parseAllArchDocs } from '../utils/arch-docs-parser.js'; -import { runSemgrepAnalysis, summarizeSemgrepFindings, filterFindingsByChangedFiles } from '../utils/semgrep-runner.js'; -import { SemgrepResult, SemgrepSummary, SemgrepFinding } from '../types/semgrep.types.js'; +import { + isTestFile, + isCodeFile, + detectTestFramework, + generateTestTemplate, + suggestTestFilePath, + analyzeTestQuality, + formatTestEnhancement, +} from '../tools/test-suggestion-tool.js'; +import { + isDevOpsFile, + analyzeDevOpsFiles, +} from '../tools/devops-cost-estimator.js'; +import { + detectCoverageTool, + readCoverageReport, +} from '../tools/coverage-reporter.js'; +import { + classifyProject, + formatClassification, +} from '../tools/project-classifier.js'; +import { getProjectClassification } from '../db/index.js'; /** * Agent workflow state @@ -46,16 +80,16 @@ export const PRAgentState = Annotation.Root({ default: () => '', }), - fixes: Annotation>({ + currentRisks: Annotation({ reducer: (_, update) => update, default: () => [], }), + currentComplexity: Annotation({ + reducer: (_, update) => update, + default: () => 1, + }), + // Quality metrics clarityScore: Annotation({ reducer: (_, update) => update, @@ -105,23 +139,14 @@ export const PRAgentState = Annotation.Root({ reducer: (current, update) => current + update, default: () => 0, }), - - // Semgrep static analysis - semgrepResult: Annotation({ - reducer: (_, update) => update, - default: () => null, - }), - - semgrepSummary: Annotation({ - reducer: (_, update) => update, - default: () => null, - }), }); /** * Configuration for PR agent workflow */ export interface PRAgentWorkflowConfig { + maxIterations: number; + clarityThreshold: number; skipSelfRefinement?: boolean; } @@ -129,14 +154,21 @@ export interface PRAgentWorkflowConfig { * Base class for PR agents with self-refinement workflow */ export abstract class BasePRAgentWorkflow { - protected model: BaseChatModel; - protected workflow: ReturnType; + protected model?: BaseChatModel; // Now optional! + protected mode: ExecutionMode; + protected workflow?: ReturnType; // Optional in PROMPT_ONLY mode protected checkpointer = new MemorySaver(); protected tools: any[]; - constructor(model: BaseChatModel) { + constructor(mode: ExecutionMode = ExecutionMode.EXECUTE, model?: BaseChatModel) { + this.mode = mode; this.model = model; + // Validation: LLM required in EXECUTE mode + if (mode === ExecutionMode.EXECUTE && !model) { + throw new Error('BasePRAgentWorkflow: LLM is required when mode is EXECUTE'); + } + // Initialize tools this.tools = [ createFileAnalyzerTool(), @@ -145,7 +177,10 @@ export abstract class BasePRAgentWorkflow { createSummaryGeneratorTool(), ]; - this.workflow = this.buildWorkflow(); + // Only build workflow in EXECUTE mode + if (mode === ExecutionMode.EXECUTE) { + this.workflow = this.buildWorkflow(); + } } /** @@ -154,22 +189,35 @@ export abstract class BasePRAgentWorkflow { private buildWorkflow() { const graph = new StateGraph(PRAgentState); - // Define nodes - simplified workflow + // Define nodes graph.addNode('analyzeFiles', this.analyzeFilesNode.bind(this)); - graph.addNode('runStaticAnalysis', this.runStaticAnalysisNode.bind(this)); - graph.addNode('generateFixes', this.generateFixesNode.bind(this)); + graph.addNode('detectRisks', this.detectRisksNode.bind(this)); + graph.addNode('calculateComplexity', this.calculateComplexityNode.bind(this)); graph.addNode('generateSummary', this.generateSummaryNode.bind(this)); + graph.addNode('evaluateQuality', this.evaluateQualityNode.bind(this)); + graph.addNode('refineAnalysis', this.refineAnalysisNode.bind(this)); graph.addNode('finalize', this.finalizeNode.bind(this)); // Set entry point const entryPoint = 'analyzeFiles' as '__start__'; graph.setEntryPoint(entryPoint); - // Build simplified linear workflow graph - graph.addEdge(entryPoint, 'runStaticAnalysis' as '__start__'); - graph.addEdge('runStaticAnalysis' as '__start__', 'generateFixes' as '__start__'); - graph.addEdge('generateFixes' as '__start__', 'generateSummary' as '__start__'); - graph.addEdge('generateSummary' as '__start__', 'finalize' as '__start__'); + // Build workflow graph + graph.addEdge(entryPoint, 'detectRisks' as '__start__'); + graph.addEdge('detectRisks' as '__start__', 'calculateComplexity' as '__start__'); + graph.addEdge('calculateComplexity' as '__start__', 'generateSummary' as '__start__'); + graph.addEdge('generateSummary' as '__start__', 'evaluateQuality' as '__start__'); + + // Conditional: refine or finalize + graph.addConditionalEdges('evaluateQuality' as '__start__', this.shouldRefine.bind(this), { + refine: 'refineAnalysis' as '__start__', + finalize: 'finalize' as '__start__', + }); + + // After refinement, evaluate again + graph.addEdge('refineAnalysis' as '__start__', 'evaluateQuality' as '__start__'); + + // End after finalization graph.addEdge('finalize' as '__start__', END); return graph.compile({ checkpointer: this.checkpointer }); @@ -177,8 +225,210 @@ export abstract class BasePRAgentWorkflow { /** * Execute the agent workflow + * Routes to either EXECUTE mode (run analysis) or PROMPT_ONLY mode (return prompts) + */ + async execute(context: AgentContext, options?: AgentExecutionOptions): Promise { + if (this.mode === ExecutionMode.PROMPT_ONLY) { + return await this.buildAllPrompts(context); + } else { + return this.executeAnalysis(context, options); + } + } + + /** + * Build all prompts for PROMPT_ONLY mode (without executing them) + * Also runs static analysis tools that don't require an LLM + */ + private async buildAllPrompts(context: AgentContext): Promise { + const files = parseDiff(context.diff); + const prompts: AnalysisPrompt[] = []; + + // Build arch-docs context if available + let archDocsContext = ''; + if (context.archDocs?.available) { + archDocsContext = formatArchDocsForPrompt(context.archDocs); + } + + // === RUN STATIC ANALYSIS (no LLM needed) === + // These features run immediately and results are included in the output + console.log('🔧 Running static analysis tools...'); + const staticAnalysis = await this.detectAndAnalyzeChangeTypes(files, context); + console.log(`✅ Static analysis complete`); + + // 1. File Analysis Prompts (for important files) + const filesToAnalyze = files.slice(0, 15); + const importantFiles = filesToAnalyze.filter(f => + f.additions + f.deletions > 20 || + f.path.includes('config') || + f.path.includes('schema') || + f.path.includes('migration') || + f.path.includes('test') + ).slice(0, 5); + + if (importantFiles.length > 0) { + prompts.push(this.buildFileAnalysisPrompt(importantFiles, archDocsContext)); + } + + // 2. Risk Detection Prompt + prompts.push(this.buildRiskDetectionPrompt(files, archDocsContext, context)); + + // 3. Summary Generation Prompt + prompts.push(this.buildSummaryPrompt(files, archDocsContext, context)); + + // 4. Self Refinement Prompt (placeholder - would need analysis results) + // Note: This would typically need results from previous steps + // For now, we'll skip it in PROMPT_ONLY mode or make it conditional + + return { + mode: 'prompt_only', + context, + prompts, + // Include static analysis results + staticAnalysis, + instructions: `Execute these prompts sequentially using your LLM: +1. First, analyze the important files in the PR +2. Then detect risks and security issues +3. Generate an overall PR summary +4. (Optional) Refine the analysis based on results + +Each prompt includes the necessary context and instructions for execution. + +Note: Static analysis (test suggestions, DevOps costs, coverage reports) has already been run and is included below.` + }; + } + + /** + * Build file analysis prompt + */ + private buildFileAnalysisPrompt(importantFiles: DiffFile[], archDocsContext: string): AnalysisPrompt { + const prompt = `Analyze these files from a pull request. For EACH file, provide a detailed analysis considering the repository's architecture standards. +${archDocsContext ? '\n' + archDocsContext : ''} + +Files to analyze: +${importantFiles.map(f => ` +File: ${f.path} +Status: ${f.status || 'modified'} +Changes: +${f.additions} -${f.deletions} +Diff preview: +\`\`\` +${f.diff.substring(0, 500)} +\`\`\` +`).join('\n---\n')} + +${archDocsContext ? `CRITICAL INSTRUCTIONS: +- For EACH file, reference the relevant architecture documentation sections above +- Explain how the changes align with or diverge from established patterns +- Identify specific guidelines that apply to each file +- Mention which parts of the architecture are affected +- Compare changes against documented standards + +` : ''} + +Respond with a JSON object mapping file paths to analysis objects: +{ + "path/to/file": { + "summary": "Description that references relevant arch-docs patterns/guidelines", + "risks": ["risk with arch-docs context", "risk2"], + "complexity": 1-5, + "recommendations": ["recommendation based on arch-docs standards"] + } +} + +${archDocsContext ? 'Each summary MUST reference the specific architecture documentation that applies to this file.' : ''}`; + + return { + step: 'fileAnalysis', + prompt, + context: { fileCount: importantFiles.length }, + instructions: 'Analyze each file and return JSON object with file analyses' + }; + } + + /** + * Build risk detection prompt */ - async execute(context: AgentContext, options?: AgentExecutionOptions): Promise { + private buildRiskDetectionPrompt(files: DiffFile[], archDocsContext: string, context: AgentContext): AnalysisPrompt { + const prompt = `Review this pull request for potential risks, security issues, and code quality problems. + +${archDocsContext ? archDocsContext : ''} + +Files changed (${files.length} total): +${files.map(f => `- ${f.path} (+${f.additions}/-${f.deletions})`).join('\n')} + +Full diff: +\`\`\`diff +${context.diff.substring(0, 8000)} +\`\`\` + +${archDocsContext ? `You have access to architecture documentation. Reference relevant security guidelines when identifying risks. + +Return a JSON array of risk objects with archDocsSource and archDocsExcerpt: +[ + { + "file": "path/to/file", + "line": 42, + "comment": "Description of risk", + "severity": "critical|warning|suggestion", + "archDocsSource": "security.md", + "archDocsExcerpt": "Relevant excerpt from arch-docs", + "reason": "Why this is a risk based on arch-docs" + } +] + +DO NOT return simple string arrays. Each risk MUST be an object with archDocsSource, archDocsExcerpt, and reason fields.` : '["risk 1", "risk 2", ...]'} + +Only include risks that are actually present. If no significant risks, return an empty array [].`; + + return { + step: 'riskDetection', + prompt, + context: { fileCount: files.length }, + instructions: 'Detect risks and return JSON array of risk objects' + }; + } + + /** + * Build summary generation prompt + */ + private buildSummaryPrompt(files: DiffFile[], archDocsContext: string, context: AgentContext): AnalysisPrompt { + const prompt = `Generate a comprehensive summary of this pull request. + +${archDocsContext ? archDocsContext : ''} + +PR Title: ${context.title || 'Untitled PR'} + +Files changed: ${files.length} +Total additions: +${files.reduce((sum, f) => sum + f.additions, 0)} +Total deletions: -${files.reduce((sum, f) => sum + f.deletions, 0)} + +Key files: +${files.slice(0, 10).map(f => `- ${f.path} (+${f.additions}/-${f.deletions})`).join('\n')} + +Diff excerpt: +\`\`\`diff +${context.diff.substring(0, 5000)} +\`\`\` + +${archDocsContext ? 'Consider the design patterns and architecture from the repository documentation when analyzing the changes.\n' : ''} + +Provide a detailed, well-structured summary (3-5 paragraphs) that would help a reviewer understand the scope and purpose of this PR.`; + + return { + step: 'summaryGeneration', + prompt, + context: {}, + instructions: 'Generate detailed PR summary (3-5 paragraphs)' + }; + } + + /** + * Execute the agent workflow in EXECUTE mode (with LLM) + */ + private async executeAnalysis(context: AgentContext, options?: AgentExecutionOptions): Promise { + if (!this.workflow) { + throw new Error('Workflow not initialized - executeAnalysis should only be called in EXECUTE mode'); + } + const startTime = Date.now(); // Fast path: skip self-refinement @@ -186,12 +436,19 @@ export abstract class BasePRAgentWorkflow { return this.executeFastPath(context, startTime); } + const config: PRAgentWorkflowConfig = { + maxIterations: 3, + clarityThreshold: 80, + skipSelfRefinement: false, + }; + const initialState = { context, iteration: 0, fileAnalyses: new Map(), currentSummary: '', - fixes: [], + currentRisks: [], + currentComplexity: 1, clarityScore: 0, missingInformation: [], recommendations: [], @@ -199,15 +456,13 @@ export abstract class BasePRAgentWorkflow { reasoning: [], totalInputTokens: 0, totalOutputTokens: 0, - semgrepResult: null, - semgrepSummary: null, - archDocsInfluencedStages: [], - archDocsKeyInsights: [], }; const workflowConfig = { configurable: { thread_id: `pr-agent-${Date.now()}`, + maxIterations: config.maxIterations, + clarityThreshold: config.clarityThreshold, }, recursionLimit: 50, }; @@ -252,19 +507,34 @@ export abstract class BasePRAgentWorkflow { keyInsights: [...new Set(stateAny.archDocsKeyInsights || [])], } : undefined; - // Build static analysis summary - const staticAnalysis = stateAny.semgrepSummary ? { - enabled: true, - totalFindings: stateAny.semgrepSummary.totalFindings, - errorCount: stateAny.semgrepSummary.errorCount, - warningCount: stateAny.semgrepSummary.warningCount, - criticalIssues: stateAny.semgrepSummary.criticalFindings.map((f: SemgrepFinding) => f.extra.message).slice(0, 5), - } : undefined; + // Smart change detection - only include relevant outputs + const files = parseDiff(context.diff); + const enhancedResult = await this.detectAndAnalyzeChangeTypes(files, context); + + // Convert currentRisks to fixes format for backward compatibility + const fixes = finalState.currentRisks.map((risk: any) => { + // Risk can be a string or RiskItem object + if (typeof risk === 'string') { + return { + file: '', + comment: risk, + severity: 'warning' as const, + }; + } + return { + file: risk.file || '', + line: risk.line, + comment: risk.description || risk.reason || String(risk), + severity: (risk.severity as 'critical' | 'warning' | 'suggestion') || 'warning', + }; + }); return { summary: finalState.currentSummary, fileAnalyses: finalState.fileAnalyses, - fixes: finalState.fixes, + fixes, + overallComplexity: finalState.currentComplexity, + overallRisks: finalState.currentRisks, recommendations: finalState.recommendations, insights: finalState.insights, reasoning: finalState.reasoning, @@ -274,7 +544,8 @@ export abstract class BasePRAgentWorkflow { executionTime, mode: context.mode, archDocsImpact, - staticAnalysis, + // Conditionally include new features based on change types + ...enhancedResult, }; } @@ -288,7 +559,8 @@ export abstract class BasePRAgentWorkflow { iteration: 0, fileAnalyses: new Map(), currentSummary: '', - fixes: [], + currentRisks: [] as string[], + currentComplexity: 1, clarityScore: 0, missingInformation: [] as string[], recommendations: [] as string[], @@ -296,8 +568,6 @@ export abstract class BasePRAgentWorkflow { reasoning: [] as string[], totalInputTokens: 0, totalOutputTokens: 0, - semgrepResult: null, - semgrepSummary: null, }; // Execute workflow nodes sequentially (skip refinement loop) @@ -306,17 +576,20 @@ export abstract class BasePRAgentWorkflow { try { // 1. Analyze files state = await this.analyzeFilesNode(state); - - // 2. Run static analysis - state = await this.runStaticAnalysisNode(state); - - // 3. Generate fixes - state = await this.generateFixesNode(state); - + + // 2. Detect risks + state = await this.detectRisksNode(state); + + // 3. Calculate complexity + state = await this.calculateComplexityNode(state); + // 4. Generate summary state = await this.generateSummaryNode(state); - - // 5. Finalize (includes recommendations) + + // 5. Generate recommendations (skip quality evaluation) + state = await this.refineAnalysisNode(state); + + // 6. Finalize state = await this.finalizeNode(state); const executionTime = Date.now() - startTime; @@ -331,19 +604,34 @@ export abstract class BasePRAgentWorkflow { keyInsights: [...new Set(stateAny.archDocsKeyInsights || [])], } : undefined; - // Build static analysis summary - const staticAnalysis = state.semgrepSummary ? { - enabled: true, - totalFindings: state.semgrepSummary.totalFindings, - errorCount: state.semgrepSummary.errorCount, - warningCount: state.semgrepSummary.warningCount, - criticalIssues: state.semgrepSummary.criticalFindings.map((f: SemgrepFinding) => f.extra.message).slice(0, 5), - } : undefined; + // Smart change detection - only include relevant outputs + const files = parseDiff(context.diff); + const enhancedResult = await this.detectAndAnalyzeChangeTypes(files, context); + + // Convert currentRisks to fixes format for backward compatibility + const fixes = state.currentRisks.map((risk: any) => { + // Risk can be a string or RiskItem object + if (typeof risk === 'string') { + return { + file: '', + comment: risk, + severity: 'warning' as const, + }; + } + return { + file: risk.file || '', + line: risk.line, + comment: risk.description || risk.reason || String(risk), + severity: (risk.severity as 'critical' | 'warning' | 'suggestion') || 'warning', + }; + }); return { summary: state.currentSummary, fileAnalyses: state.fileAnalyses, - fixes: state.fixes, + fixes, + overallComplexity: state.currentComplexity, + overallRisks: state.currentRisks, recommendations: state.recommendations, insights: state.insights, reasoning: [...state.reasoning, 'Fast path: Self-refinement evaluation skipped for speed'], @@ -353,7 +641,8 @@ export abstract class BasePRAgentWorkflow { executionTime, mode: context.mode, archDocsImpact, - staticAnalysis, + // Conditionally include new features based on change types + ...enhancedResult, }; } catch (error) { console.error('Fast path execution error:', error); @@ -361,14 +650,182 @@ export abstract class BasePRAgentWorkflow { } } + /** + * Smart change detection - analyzes files and returns only relevant enhanced features + */ + private async detectAndAnalyzeChangeTypes( + files: Array<{ path: string; diff: string; additions: number; deletions: number }>, + context: AgentContext + ): Promise<{ + testSuggestions?: TestSuggestion[]; + devOpsCostEstimates?: DevOpsCostEstimate[]; + coverageReport?: CoverageReport; + projectClassification?: string; + }> { + const result: { + testSuggestions?: TestSuggestion[]; + devOpsCostEstimates?: DevOpsCostEstimate[]; + coverageReport?: CoverageReport; + projectClassification?: string; + } = {}; + + // === PROJECT CLASSIFICATION === + // Check DB cache first, only run classification if not cached (saves tokens) + const repoOwner = (context.config?.repoOwner as string) || 'local'; + const repoName = (context.config?.repoName as string) || 'unknown'; + + let cachedClassification = getProjectClassification(repoOwner, repoName); + + if (cachedClassification) { + // Use cached classification + result.projectClassification = cachedClassification; + } else { + // Run classification and store for caching + const classification = classifyProject( + files.map(f => ({ filename: f.path, patch: f.diff })) + ); + result.projectClassification = formatClassification(classification); + } + + // Categorize files by type + const codeFiles = files.filter(f => isCodeFile(f.path) && !isTestFile(f.path)); + const testFiles = files.filter(f => isTestFile(f.path)); + const devOpsFiles = files.filter(f => isDevOpsFile(f.path).isDevOps); + + console.log(`📊 Change Analysis: ${codeFiles.length} code files, ${testFiles.length} test files, ${devOpsFiles.length} DevOps files`); + + // 1. Developer changes without tests → Test Suggestions + if (codeFiles.length > 0 && codeFiles.length > testFiles.length) { + console.log(`🧪 Detecting test suggestions for ${codeFiles.length} code files...`); + + const frameworkInfo = detectTestFramework(context.config?.repoPath as string || '.'); + const testSuggestions: TestSuggestion[] = []; + + for (const file of codeFiles) { + // Check if there's a corresponding test file in the PR + const baseName = file.path.replace(/\.[^/.]+$/, '').split('/').pop() || ''; + const hasTest = testFiles.some(t => + t.path.toLowerCase().includes(baseName.toLowerCase()) + ); + + if (!hasTest && file.additions > 5) { + // Extract function names from diff for better test generation + const functionMatches = file.diff.match(/(?:function|const|let|var|async)\s+(\w+)/g) || []; + const functionNames = functionMatches + .map(m => m.replace(/(?:function|const|let|var|async)\s+/, '')) + .filter(name => name.length > 2 && !['the', 'and', 'for'].includes(name)); + + const testCode = generateTestTemplate( + frameworkInfo.framework, + file.path, + file.diff, + functionNames.slice(0, 5) + ); + + testSuggestions.push({ + forFile: file.path, + testFramework: frameworkInfo.framework, + testCode, + description: `Suggested tests for new/modified code in ${file.path}`, + testFilePath: suggestTestFilePath(file.path, frameworkInfo.framework), + }); + } + } + + if (testSuggestions.length > 0) { + result.testSuggestions = testSuggestions; + console.log(`✅ Generated ${testSuggestions.length} test suggestions`); + } + } + + // 1b. Existing tests → Test Enhancement Suggestions + if (testFiles.length > 0 && codeFiles.length > 0) { + console.log(`🔬 Analyzing ${testFiles.length} existing test file(s) for improvements...`); + + const frameworkInfo = detectTestFramework(context.config?.repoPath as string || '.'); + + for (const testFile of testFiles) { + // Find corresponding source file + const baseName = testFile.path + .replace(/\.(test|spec)\./i, '.') + .replace(/^(test|tests|__tests__)\//i, '') + .replace(/\/(test|tests|__tests__)\//i, '/'); + + const sourceFile = codeFiles.find(f => + f.path.includes(baseName.split('/').pop()?.replace(/\.[^.]+$/, '') || '') + ); + + if (sourceFile && testFile.additions > 0) { + // Analyze test quality and suggest enhancements + const enhancement = analyzeTestQuality( + { path: testFile.path, diff: testFile.diff }, + { path: sourceFile.path, diff: sourceFile.diff }, + frameworkInfo.framework + ); + + if (enhancement.suggestions.length > 0) { + // Add as test suggestion with enhancement flag + result.testSuggestions = result.testSuggestions || []; + result.testSuggestions.push({ + forFile: sourceFile.path, + testFramework: frameworkInfo.framework, + testCode: enhancement.enhancementCode || '', + description: `Test enhancements for ${path.basename(testFile.path)}: ${enhancement.suggestions.join(', ')}`, + testFilePath: testFile.path, + isEnhancement: true, + existingTestFile: testFile.path, + }); + + console.log(` → Found ${enhancement.missingScenarios.length} missing scenario(s) in ${path.basename(testFile.path)}`); + } + } + } + + const enhancementCount = result.testSuggestions?.filter(s => s.isEnhancement).length || 0; + if (enhancementCount > 0) { + console.log(`✅ Generated ${enhancementCount} test enhancement suggestion(s)`); + } + } + + // 2. DevOps/IaC changes → Cost Estimation + if (devOpsFiles.length > 0) { + console.log(`💰 Analyzing DevOps costs for ${devOpsFiles.length} files...`); + + const costAnalysis = analyzeDevOpsFiles(devOpsFiles); + + if (costAnalysis.hasDevOpsChanges && costAnalysis.estimates.length > 0) { + result.devOpsCostEstimates = costAnalysis.estimates; + console.log(`✅ Estimated costs for ${costAnalysis.estimates.length} resources (~$${costAnalysis.totalEstimatedCost.toFixed(2)}/month)`); + } + } + + // 3. Test/QA changes → Coverage Report (only if configured) + if (testFiles.length > 0 || codeFiles.length > 0) { + const coverageConfig = detectCoverageTool(context.config?.repoPath as string || '.'); + + if (coverageConfig.configured) { + console.log(`📊 Checking coverage (${coverageConfig.tool} detected)...`); + + const coverage = readCoverageReport(context.config?.repoPath as string || '.'); + + if (coverage.available) { + result.coverageReport = coverage; + console.log(`✅ Coverage: ${coverage.overallPercentage?.toFixed(1)}%`); + } + } + } + + return result; + } + // Workflow nodes private async analyzeFilesNode(state: typeof PRAgentState.State) { const { context } = state; const files = parseDiff(context.diff); - + console.log(`🔍 Analyzing ${files.length} files...`); - + // Show arch-docs status if available if (context.archDocs?.available) { console.log(`📚 Using architecture documentation (${context.archDocs.totalDocs} docs, ${context.archDocs.relevantDocs.length} relevant sections)`); @@ -384,9 +841,9 @@ export abstract class BasePRAgentWorkflow { // Analyze files in batches for detailed insights const filesToAnalyze = files.slice(0, 15); // Limit to 15 files for detailed analysis - const importantFiles = filesToAnalyze.filter(f => + const importantFiles = filesToAnalyze.filter(f => f.additions + f.deletions > 20 || // Significant changes - f.path.includes('config') || + f.path.includes('config') || f.path.includes('schema') || f.path.includes('migration') || f.path.includes('test') @@ -396,6 +853,10 @@ export abstract class BasePRAgentWorkflow { if (importantFiles.length > 0) { try { + if (!this.model) { + throw new Error('LLM is required for file analysis in EXECUTE mode'); + } + const fileDetailsPrompt = `Analyze these files from a pull request. For EACH file, provide a detailed analysis considering the repository's architecture standards. ${archDocsContext ? '\n' + archDocsContext : ''} @@ -433,7 +894,7 @@ ${archDocsContext ? 'Each summary MUST reference the specific architecture docum const response = await this.model.invoke(fileDetailsPrompt); const content = response.content as string; - + // Track tokens const usage = (response.response_metadata as any)?.usage; const inputTokens = usage?.input_tokens || 0; @@ -444,7 +905,7 @@ ${archDocsContext ? 'Each summary MUST reference the specific architecture docum const jsonMatch = content.match(/\{[\s\S]*\}/); if (jsonMatch) { const detailedAnalyses = JSON.parse(jsonMatch[0]); - + // Apply detailed analysis to file analyses for (const file of importantFiles) { const detail = detailedAnalyses[file.path]; @@ -502,7 +963,7 @@ ${archDocsContext ? 'Each summary MUST reference the specific architecture docum const hasArchDocsContext = archDocsContext && archDocsContext.length > 0; const archDocsStages = hasArchDocsContext ? ['file-analysis'] : []; const archDocsInsights = []; - + if (hasArchDocsContext && context.archDocs?.available) { archDocsInsights.push(`Applied ${context.archDocs.relevantDocs.length} architecture documentation sections to analyze files in context of repository standards`); } @@ -516,262 +977,287 @@ ${archDocsContext ? 'Each summary MUST reference the specific architecture docum }; } - private async runStaticAnalysisNode(state: typeof PRAgentState.State) { - const { context } = state; - - // Skip if static analysis is disabled - if (!context.enableStaticAnalysis) { - console.log('⏭️ Static analysis disabled, skipping...'); - return state; - } - - - try { - // Get current working directory for analysis - const targetPath = process.cwd(); - - // Run Semgrep analysis - const semgrepResult = await runSemgrepAnalysis( - targetPath, - { - enabled: true, - timeout: 30, - maxFileSize: 1000000, // 1MB - excludePaths: [ - '**/node_modules/**', - '**/dist/**', - '**/build/**', - '**/.git/**', - '**/*.min.js', - '**/*.map', - ], - }, - context.language, - context.framework, - ); - - // Check for errors - if (semgrepResult.errors && semgrepResult.errors.length > 0) { - const hasBlockingError = semgrepResult.errors.some(e => e.level === 'error' && e.type === 'semgrep_not_installed'); - if (hasBlockingError) { - console.log('ℹ️ Semgrep not available, continuing without static analysis'); - return state; - } - } + private async detectRisksNode(state: typeof PRAgentState.State) { + const { context, fileAnalyses } = state; - // Filter findings to only include changed files - const changedFilePaths = context.files.map(f => f.path); - const relevantFindings = filterFindingsByChangedFiles(semgrepResult.results || [], changedFilePaths); + console.log('⚠️ Detecting risks...'); - // Create filtered result - const filteredResult: SemgrepResult = { - ...semgrepResult, - results: relevantFindings, - }; - - // Summarize findings - const summary = summarizeSemgrepFindings(filteredResult); - - console.log(` Found ${summary.totalFindings} issues (${summary.errorCount} errors, ${summary.warningCount} warnings)`); - - return { - ...state, - semgrepResult: filteredResult, - semgrepSummary: summary, - insights: [`Static analysis: ${summary.totalFindings} findings in changed files`], - }; - } catch (error) { - console.error('Error running static analysis:', error); - return { - ...state, - insights: ['Static analysis encountered an error and was skipped'], - }; - } - } - - private async generateFixesNode(state: typeof PRAgentState.State) { - const { context, fileAnalyses, semgrepSummary, semgrepResult } = state; - - console.log('🔧 Generating fixes...'); - - // If static analysis is enabled, convert Semgrep findings to fixes - if (context.enableStaticAnalysis && semgrepResult && semgrepSummary && semgrepSummary.totalFindings > 0) { - console.log(' Converting Semgrep findings to fixes'); - const fixes = semgrepResult.results.map((finding: SemgrepFinding) => ({ - file: finding.path, - line: finding.start.line, - comment: `${finding.extra.severity === 'ERROR' ? '🔴 **Critical**: ' : finding.extra.severity === 'WARNING' ? '🟡 **Warning**: ' : 'ℹ️ '}${finding.extra.message}\n\n**Rule**: ${finding.check_id}${finding.extra.metadata?.cwe ? `\n**CWE**: ${finding.extra.metadata.cwe.join(', ')}` : ''}${finding.extra.metadata?.owasp ? `\n**OWASP**: ${finding.extra.metadata.owasp.join(', ')}` : ''}`, - severity: finding.extra.severity === 'ERROR' ? 'critical' as const : finding.extra.severity === 'WARNING' ? 'warning' as const : 'suggestion' as const, - source: 'semgrep' as const, - })); - - return { - ...state, - fixes, - insights: [`Generated ${fixes.length} fixes from Semgrep findings`], - }; - } - - // Otherwise, do AI-based fix generation - console.log(' Running AI-based fix generation'); - - // Parse diff to get file paths and line numbers - const files = parseDiff(context.diff); + // Build context for risk analysis const fileList = Array.from(fileAnalyses.entries()) .slice(0, 15) - .map(([path, analysis]) => + .map(([path, analysis]) => `${path} (+${analysis.changes.additions} -${analysis.changes.deletions})` ) .join('\n'); - // Get diff sample with line numbers - const diffSample = context.diff.substring(0, 12000); + // Get a sample of the diff for risk analysis (limit size) + const diffSample = context.diff.substring(0, 8000); // First 8KB for context // Add security context from arch-docs if available let securityContext = ''; let allDocs: any[] = []; - + let securityDoc: any = null; + let patternsDoc: any = null; + if (context.archDocs?.available) { allDocs = parseAllArchDocs(); const secDoc = getSecurityContext(allDocs); if (secDoc) { securityContext = `\n## Security Guidelines from Repository Documentation\n\n${secDoc.substring(0, 3000)}\n`; + securityDoc = allDocs.find(d => d.filename === 'security'); } - + + // Also get patterns that might indicate risks const patterns = getPatternsContext(allDocs); if (patterns) { securityContext += `\n## Repository Patterns and Best Practices\n\n${patterns.substring(0, 2000)}\n`; + patternsDoc = allDocs.find(d => d.filename === 'patterns'); } } - const fixesPrompt = `You are a code reviewer analyzing a pull request. Generate CRUCIAL, actionable fixes as PR comments. + const riskPrompt = `You are a security and code quality expert analyzing a pull request for potential risks. ${securityContext} -Analyze the following changes and identify issues that NEED to be fixed. Focus on: -1. **Security Issues**: Exposed credentials, insecure patterns, authentication/authorization problems -2. **Critical Bugs**: Logic errors, null pointer risks, race conditions -3. **Breaking Changes**: API changes without versioning, removed functionality -4. **Code Quality**: Missing error handling, code smells, anti-patterns -5. **Performance**: Inefficient algorithms, memory leaks, N+1 queries +Analyze the following changes and identify SPECIFIC risks in these categories: +1. **Security Risks**: Exposed credentials, insecure patterns, authentication/authorization issues +2. **Breaking Changes**: API changes, database schema changes, removed functionality +3. **Performance Concerns**: Inefficient algorithms, memory leaks, N+1 queries +4. **Code Quality**: Complex logic, missing error handling, lack of tests +5. **Operational Risks**: Configuration changes, deployment concerns, dependency updates PR Title: ${context.title || 'No title provided'} Files changed: ${fileList} -Diff: +Diff sample: \`\`\` ${diffSample} \`\`\` -${securityContext ? `IMPORTANT: Reference repository documentation when applicable.` : ''} +${securityContext ? `CRITICAL INSTRUCTIONS: +- You MUST reference the repository documentation guidelines above when identifying each risk +- For EVERY risk you identify, find the relevant guideline from the documentation +- Explain HOW the code change violates or conflicts with the documented standards +- Quote the specific guideline that makes this a risk +- Be specific about why this matters based on the repository's own standards + +Example format for a risk with documentation: +{ + "description": "File exceeds maximum line count recommended for maintainability", + "archDocsSource": "code-quality.md", + "archDocsExcerpt": "Keep individual files under 500 lines to maintain testability and readability", + "reason": "This file contains 990 lines, nearly 2x the repository standard, which increases maintenance burden and makes comprehensive testing more difficult" +} +` : ''} -For EACH issue found, provide: -- **file**: The file path where the issue exists -- **line**: Approximate line number (if you can identify it from the diff, otherwise omit) -- **comment**: Actionable PR comment explaining the issue and how to fix it. Be specific and helpful. -- **severity**: "critical" (must fix), "warning" (should fix), or "suggestion" (nice to have) +Provide a JSON array of risk objects. Each risk MUST include: +- description: Clear, specific description of the risk +${securityContext ? `- archDocsSource: REQUIRED - Which documentation file from above this relates to (e.g., "security.md", "patterns.md", "code-quality.md") +- archDocsExcerpt: REQUIRED - Direct quote from the repository documentation that this violates +- reason: REQUIRED - Detailed explanation of why this is a risk based on the specific guideline quoted above +` : ''} -Return a JSON array of fix objects: -[ +Format: +${securityContext ? `[ { - "file": "src/path/to/file.ts", - "line": 42, - "comment": "**Security Issue**: Hardcoded API key detected. Use environment variables instead.\n\n**Fix**: Move to process.env.API_KEY or use a secrets manager.", - "severity": "critical" - }, - { - "file": "src/utils/helper.ts", - "comment": "**Missing Error Handling**: This function can throw but errors aren't caught.\n\n**Fix**: Wrap in try-catch or add error handling.", - "severity": "warning" + "description": "Specific risk description", + "archDocsSource": "documentation-file.md", + "archDocsExcerpt": "Exact quote from the documentation", + "reason": "Detailed explanation connecting the code change to the guideline violation" } ] -Only include CRUCIAL fixes that matter. If no significant issues, return an empty array [].`; +DO NOT return simple string arrays. Each risk MUST be an object with archDocsSource, archDocsExcerpt, and reason fields.` : '["risk 1", "risk 2", ...]'} + +Only include risks that are actually present. If no significant risks, return an empty array [].`; try { - const response = await this.model.invoke(fixesPrompt); + if (!this.model) { + throw new Error('LLM is required for risk detection in EXECUTE mode'); + } + + const response = await this.model.invoke(riskPrompt); const content = response.content as string; - + // Track tokens const usage = (response.response_metadata as any)?.usage; const inputTokens = usage?.input_tokens || 0; const outputTokens = usage?.output_tokens || 0; // Parse JSON response - let fixes: Array<{file: string; line?: number; comment: string; severity?: 'critical' | 'warning' | 'suggestion'; source?: 'semgrep' | 'ai'}> = []; - + let risks: any[] = []; + let hasArchDocsEnhancement = false; + try { // Extract JSON from markdown code blocks if present const jsonMatch = content.match(/\[[\s\S]*\]/); if (jsonMatch) { - const parsedFixes = JSON.parse(jsonMatch[0]); - fixes = parsedFixes - .filter((f: any) => f.file && f.comment) - .map((f: any) => ({ - file: f.file, - line: f.line, - comment: f.comment, - severity: f.severity || 'warning', - source: 'ai' as const, - })) - // Prioritize critical and warning fixes, limit suggestions - .sort((a: any, b: any) => { - const severityOrder: Record = { critical: 0, warning: 1, suggestion: 2 }; - const aSeverity = a.severity || 'warning'; - const bSeverity = b.severity || 'warning'; - return (severityOrder[aSeverity] ?? 2) - (severityOrder[bSeverity] ?? 2); - }) - // Limit to top 10 fixes (prioritize critical/warning) - .slice(0, 10); + const parsedRisks = JSON.parse(jsonMatch[0]); + + // Check if risks have arch-docs references + if (parsedRisks.length > 0 && typeof parsedRisks[0] === 'object' && 'archDocsSource' in parsedRisks[0]) { + // Transform to our RiskItem format + risks = parsedRisks.map((r: any) => ({ + description: r.description, + archDocsReference: r.archDocsSource ? { + source: r.archDocsSource, + excerpt: r.archDocsExcerpt || '', + reason: r.reason || '', + } : undefined, + })); + hasArchDocsEnhancement = true; + } else if (parsedRisks.length > 0 && typeof parsedRisks[0] === 'string') { + // Legacy format - just strings + risks = parsedRisks; + } else { + risks = parsedRisks; + } } } catch (parseError) { - console.warn('Failed to parse fixes JSON:', parseError); + console.warn('Failed to parse risk JSON, extracting manually'); + // Fallback: extract bullet points as strings + const lines = content.split('\n'); + risks = lines + .filter(line => line.trim().startsWith('-') || line.trim().startsWith('•')) + .map(line => line.replace(/^[-•]\s*/, '').trim()) + .filter(line => line.length > 0); } - // Add pattern-based fixes for critical issues + // Add basic pattern-based checks with arch-docs enhancement + const patternRisks: any[] = []; if (context.diff.includes('password') || context.diff.includes('secret') || context.diff.includes('api_key')) { - const fileMatch = context.diff.match(/^diff --git a\/.*? b\/(.+)$/m); - const affectedFile = fileMatch ? fileMatch[1] : 'unknown'; - fixes.push({ - file: affectedFile, - comment: '**Security Issue**: Potential hardcoded credentials detected. Use environment variables or a secrets manager instead of hardcoding sensitive values.', - severity: 'critical', - source: 'ai' as const, - }); - } - - // Track arch-docs usage - const archDocsStages = securityContext ? ['fix-generation'] : []; + const riskDesc = 'Potential credentials or sensitive data in code changes'; + if (securityDoc) { + // Always enhance with arch-docs if available + patternRisks.push({ + description: riskDesc, + archDocsReference: { + source: 'security.md', + excerpt: 'Never commit credentials, API keys, or secrets to the repository. Use environment variables for all sensitive configuration.', + reason: 'Code changes contain keywords like "password", "secret", or "api_key" which may indicate hardcoded credentials. This violates the repository security policy requiring all secrets to be externalized via environment variables.', + }, + }); + } else { + patternRisks.push(riskDesc); + } + } + + if (fileAnalyses.size > 20) { + const qualityDoc = allDocs.find(d => d.filename === 'code-quality'); + if (qualityDoc && securityContext) { + patternRisks.push({ + description: `Large change set (${fileAnalyses.size} files) increases review complexity and error risk`, + archDocsReference: { + source: 'code-quality.md', + excerpt: 'Keep pull requests focused and under 15 files when possible for thorough review', + reason: `This PR modifies ${fileAnalyses.size} files, exceeding the recommended limit. Large PRs are harder to review thoroughly and increase the likelihood of missing critical issues.`, + }, + }); + } else { + patternRisks.push(`Large change set (${fileAnalyses.size} files) - may be difficult to review thoroughly`); + } + } + + if (context.diff.includes('DROP TABLE') || context.diff.includes('ALTER TABLE')) { + if (securityContext) { + patternRisks.push({ + description: 'Database schema changes detected - requires careful migration planning', + archDocsReference: { + source: 'patterns.md', + excerpt: 'All database schema changes must be backwards-compatible and include rollback procedures', + reason: 'The changes include database schema modifications (DROP TABLE or ALTER TABLE) which can cause data loss or application downtime if not properly planned and tested.', + }, + }); + } else { + patternRisks.push('Database schema changes detected - requires careful migration planning'); + } + } + + // Merge risks, avoiding duplicates (for string risks) + let allRisks: any[]; + if (hasArchDocsEnhancement) { + // Keep structured risks + allRisks = [...risks, ...patternRisks]; + } else { + // Deduplicate string risks + allRisks = [...new Set([...risks, ...patternRisks])]; + } + + // Track arch-docs usage in risk detection + const archDocsStages = securityContext ? ['risk-detection'] : []; const archDocsInsights = []; - - if (securityContext && context.archDocs?.available && fixes.length > 0) { - archDocsInsights.push(`Generated ${fixes.length} fixes based on repository guidelines`); + + if (securityContext && context.archDocs?.available) { + const enhancedCount = allRisks.filter(r => typeof r === 'object' && r.archDocsReference).length; + if (enhancedCount > 0) { + archDocsInsights.push(`Linked ${enhancedCount} risks to specific repository security guidelines and best practices`); + } } return { ...state, - fixes, - insights: [`Generated ${fixes.length} crucial fixes`], + currentRisks: allRisks, + insights: [`Identified ${allRisks.length} potential risks`], totalInputTokens: (state.totalInputTokens || 0) + inputTokens, totalOutputTokens: (state.totalOutputTokens || 0) + outputTokens, archDocsInfluencedStages: archDocsStages, archDocsKeyInsights: archDocsInsights, }; } catch (error) { - console.error('Error generating fixes:', error); - + console.error('Error in risk detection:', error); + + // Fallback to basic pattern matching + const basicRisks: string[] = []; + if (context.diff.includes('password') || context.diff.includes('secret')) { + basicRisks.push('Potential credentials in diff'); + } + if (fileAnalyses.size > 15) { + basicRisks.push('Large change set - difficult to review'); + } + return { ...state, - fixes: [], - insights: ['Fix generation encountered an error'], + currentRisks: basicRisks, + insights: [`Identified ${basicRisks.length} potential risks (basic analysis)`], }; } } + private async calculateComplexityNode(state: typeof PRAgentState.State) { + const { fileAnalyses, context } = state; + + console.log('📊 Calculating complexity...'); + + const complexities = Array.from(fileAnalyses.values()).map(f => f.complexity); + const avgComplexity = complexities.length > 0 + ? complexities.reduce((a, b) => a + b, 0) / complexities.length + : 1; + + // Track arch-docs influence on complexity + const archDocsStages = context.archDocs?.available ? ['complexity-calculation'] : []; + const archDocsInsights = []; + + if (context.archDocs?.available) { + // Check if patterns documentation helped understand complexity + const allDocs = parseAllArchDocs(); + const patterns = getPatternsContext(allDocs); + if (patterns) { + archDocsInsights.push(`Evaluated complexity against repository design patterns and coding standards`); + } + } + + return { + ...state, + currentComplexity: Math.round(avgComplexity), + archDocsInfluencedStages: archDocsStages, + archDocsKeyInsights: archDocsInsights, + }; + } + private async generateSummaryNode(state: typeof PRAgentState.State) { - const { context, fileAnalyses, fixes, semgrepSummary } = state; - + const { context, fileAnalyses, currentRisks, currentComplexity } = state; + console.log('📝 Generating detailed summary...'); const totalFiles = fileAnalyses.size; @@ -781,8 +1267,8 @@ Only include CRUCIAL fixes that matter. If no significant issues, return an empt // Build file list with changes const fileList = Array.from(fileAnalyses.entries()) .slice(0, 20) - .map(([path, analysis]) => - `- ${path}: +${analysis.changes.additions} -${analysis.changes.deletions}` + .map(([path, analysis]) => + `- ${path}: +${analysis.changes.additions} -${analysis.changes.deletions} (complexity: ${analysis.complexity}/5)` ) .join('\n'); @@ -796,38 +1282,39 @@ Only include CRUCIAL fixes that matter. If no significant issues, return an empt } } - // Add Semgrep summary if available - let semgrepSummaryContext = ''; - if (semgrepSummary && semgrepSummary.totalFindings > 0) { - semgrepSummaryContext = `\n## Static Analysis Summary (Semgrep)\n\n`; - semgrepSummaryContext += `- Total findings: ${semgrepSummary.totalFindings}\n`; - semgrepSummaryContext += `- Errors: ${semgrepSummary.errorCount}\n`; - semgrepSummaryContext += `- Warnings: ${semgrepSummary.warningCount}\n`; - semgrepSummaryContext += `- Categories affected: ${semgrepSummary.categoriesAffected.join(', ')}\n`; - semgrepSummaryContext += `- Files with issues: ${semgrepSummary.filesWithIssues.length}\n\n`; - } - - // Create concise prompt for quick reading - const summaryPrompt = `Analyze this pull request and provide a BRIEF, scannable summary (2-3 sentences max). + // Create comprehensive prompt for LLM + const summaryPrompt = `You are analyzing a pull request. Provide a DETAILED and COMPREHENSIVE summary that covers: -Focus on: -- **What**: What does this PR do? (one sentence) -- **Why**: What problem does it solve or what feature does it add? (one sentence) -- **Impact**: What parts of the codebase are affected? (one sentence if significant) +1. **Overall Purpose**: What is this PR trying to accomplish? What problem does it solve? +2. **Key Changes**: What are the main changes being made? Group related changes together. +3. **Impact Analysis**: What parts of the system are affected? What are the implications? +4. **Technical Details**: Mention important technical aspects (new dependencies, API changes, data model changes, etc.) +5. **Patterns Observed**: Any design patterns, refactoring, or architectural changes? +${patternsContext} PR Title: ${context.title || 'No title provided'} -${context.language ? `Language: ${context.language}${context.framework ? ` (${context.framework})` : ''}` : ''} -Stats: ${totalFiles} files, +${totalAdditions}/-${totalDeletions} lines${fixes.length > 0 ? `, ${fixes.filter((f: any) => f.severity === 'critical').length} critical fixes` : ''} +Statistics: +- Files changed: ${totalFiles} +- Lines added: ${totalAdditions} +- Lines deleted: ${totalDeletions} +- Overall complexity: ${currentComplexity}/5 +- Risks identified: ${currentRisks.length} -Key files: -${fileList.split('\n').slice(0, 5).join('\n')} +Files changed: +${fileList} + +${currentRisks.length > 0 ? `\nRisks detected:\n${currentRisks.map(r => `- ${r}`).join('\n')}` : ''} -${semgrepSummaryContext && semgrepSummary ? `Static analysis found ${semgrepSummary.totalFindings} issues (${semgrepSummary.errorCount} critical). ` : ''} +${patternsContext ? 'Consider the design patterns and architecture from the repository documentation when analyzing the changes.\n' : ''} -Write a concise summary that helps reviewers quickly understand the PR's purpose and scope. Be direct and specific.`; +Provide a detailed, well-structured summary (3-5 paragraphs) that would help a reviewer understand the scope and purpose of this PR.`; try { + if (!this.model) { + throw new Error('LLM is required for summary generation in EXECUTE mode'); + } + const response = await this.model.invoke(summaryPrompt); const detailedSummary = response.content as string; @@ -839,15 +1326,11 @@ Write a concise summary that helps reviewers quickly understand the PR's purpose // Track arch-docs usage in summary const archDocsStages = patternsContext ? ['summary-generation'] : []; const archDocsInsights = []; - + if (patternsContext && context.archDocs?.available) { archDocsInsights.push(`Generated summary aligned with repository architecture and established patterns`); } - if (semgrepSummary && semgrepSummary.totalFindings > 0) { - archDocsInsights.push(`Incorporated ${semgrepSummary.totalFindings} static analysis findings into summary`); - } - return { ...state, currentSummary: detailedSummary, @@ -863,7 +1346,8 @@ Write a concise summary that helps reviewers quickly understand the PR's purpose - Files changed: ${totalFiles} - Additions: ${totalAdditions} - Deletions: ${totalDeletions} -- Fixes identified: ${fixes.length} +- Overall complexity: ${currentComplexity}/5 +- Risks identified: ${currentRisks.length} ${context.title ? `Title: ${context.title}` : ''}`; @@ -874,50 +1358,84 @@ ${context.title ? `Title: ${context.title}` : ''}`; } } - private async finalizeNode(state: typeof PRAgentState.State) { - const { currentSummary, fixes, fileAnalyses, context } = state; - - console.log('✨ Finalizing analysis and generating recommendations...'); + private async evaluateQualityNode(state: typeof PRAgentState.State) { + const { iteration } = state; + + console.log(`🔍 Evaluating quality (iteration ${iteration + 1})...`); + + // Simple quality check + const clarityScore = 85; // Placeholder + + return { + ...state, + clarityScore, + iteration: iteration + 1, + }; + } + + private async refineAnalysisNode(state: typeof PRAgentState.State) { + const { currentSummary, currentRisks, fileAnalyses, context } = state; + + console.log('🔄 Refining analysis...'); - // Build arch-docs context for recommendations if available + // Build arch-docs context for refinement let archDocsRefinementContext = ''; if (context.archDocs?.available) { const allDocs = parseAllArchDocs(); - + // Get recommendations from arch-docs const recommendationsDoc = allDocs.find(d => d.filename === 'recommendations'); if (recommendationsDoc) { archDocsRefinementContext += `\n## Repository Improvement Guidelines\n\n${recommendationsDoc.content.substring(0, 2000)}\n`; } - + // Get code quality guidelines const qualityDoc = allDocs.find(d => d.filename === 'code-quality'); if (qualityDoc) { archDocsRefinementContext += `\n## Code Quality Standards\n\n${qualityDoc.content.substring(0, 2000)}\n`; } + + // Get KPI metrics + const kpiDoc = allDocs.find(d => d.filename === 'kpi'); + if (kpiDoc) { + archDocsRefinementContext += `\n## Repository Health KPIs\n\n${kpiDoc.content.substring(0, 1500)}\n`; + } } - // Generate recommendations - const refinementPrompt = `Based on this PR analysis, provide 3-5 specific, actionable recommendations. - ${archDocsRefinementContext} - - PR Summary: - ${currentSummary} - - Fixes Identified: ${fixes.length} - ${fixes.length > 0 ? `\nKey fixes:\n${fixes.slice(0, 5).map(f => `- ${f.file}${f.line ? `:${f.line}` : ''}: ${f.comment.substring(0, 100)}...`).join('\n')}` : ''} - - Files Changed: ${fileAnalyses.size} - - ${archDocsRefinementContext ? 'Use the repository guidelines above to ensure recommendations align with established practices.\n' : ''} - - Provide a JSON array of recommendations: - ["recommendation 1", "recommendation 2", ...]`; + // Generate comprehensive recommendations + const refinementPrompt = `Based on this PR analysis, provide specific, actionable recommendations for the developer and reviewers. +${archDocsRefinementContext} + +PR Summary: +${currentSummary} + +Risks Identified: +${currentRisks.map(r => `- ${r}`).join('\n')} + +Files Changed: ${fileAnalyses.size} + +Consider: +1. Code organization and structure improvements +2. Testing recommendations +3. Documentation needs +4. Performance optimizations +5. Security enhancements +6. Review process suggestions +${archDocsRefinementContext ? '7. Alignment with repository standards and KPIs from arch-docs\n' : ''} + +${archDocsRefinementContext ? 'Use the repository guidelines and standards above to ensure recommendations align with established practices.\n' : ''} + +Provide a JSON array of 3-5 specific, actionable recommendations: +["recommendation 1", "recommendation 2", ...]`; try { + if (!this.model) { + throw new Error('LLM is required for self refinement in EXECUTE mode'); + } + const response = await this.model.invoke(refinementPrompt); const content = response.content as string; - + // Track tokens const usage = (response.response_metadata as any)?.usage; const inputTokens = usage?.input_tokens || 0; @@ -949,12 +1467,12 @@ ${context.title ? `Title: ${context.title}` : ''}`; ]; } - // Track arch-docs usage - const archDocsStages = archDocsRefinementContext ? ['finalization'] : []; + // Track arch-docs usage in refinement + const archDocsStages = archDocsRefinementContext ? ['refinement'] : []; const archDocsInsights = []; - + if (archDocsRefinementContext && context.archDocs?.available) { - archDocsInsights.push(`Generated ${recommendations.length} recommendations based on repository quality standards`); + archDocsInsights.push(`Generated ${recommendations.length} recommendations based on repository quality standards and KPIs`); } return { @@ -962,11 +1480,11 @@ ${context.title ? `Title: ${context.title}` : ''}`; recommendations, totalInputTokens: (state.totalInputTokens || 0) + inputTokens, totalOutputTokens: (state.totalOutputTokens || 0) + outputTokens, - archDocsInfluencedStages: [...(state.archDocsInfluencedStages || []), ...archDocsStages], - archDocsKeyInsights: [...(state.archDocsKeyInsights || []), ...archDocsInsights], + archDocsInfluencedStages: archDocsStages, + archDocsKeyInsights: archDocsInsights, }; } catch (error) { - console.error('Error generating recommendations:', error); + console.error('Error refining analysis:', error); return { ...state, recommendations: [ @@ -977,5 +1495,30 @@ ${context.title ? `Title: ${context.title}` : ''}`; }; } } + + private async finalizeNode(state: typeof PRAgentState.State) { + console.log('✨ Finalizing analysis...'); + + return state; + } + + private shouldRefine(state: typeof PRAgentState.State): string { + // Use defaults if config not accessible + const maxIterations = 3; + const clarityThreshold = 80; + + if (state.iteration >= maxIterations) { + console.log(`⏹️ Stopping: Max iterations (${maxIterations}) reached`); + return 'finalize'; + } + + if (state.clarityScore >= clarityThreshold) { + console.log(`✅ Stopping: Clarity threshold (${clarityThreshold}) achieved`); + return 'finalize'; + } + + console.log(`🔄 Continuing: Iteration ${state.iteration}, clarity ${state.clarityScore}`); + return 'refine'; + } } diff --git a/src/agents/jira-sub-agent.ts b/src/agents/jira-sub-agent.ts new file mode 100644 index 0000000..9f89b86 --- /dev/null +++ b/src/agents/jira-sub-agent.ts @@ -0,0 +1,801 @@ +/** + * Jira Sub-Agent (Peer Review Agent) + * + * This agent acts like an experienced senior developer reviewing a PR. + * It understands not just the code, but the business context from the Jira ticket. + * + * KEY PHILOSOPHY: + * Like a senior developer who deeply knows the codebase, this agent: + * 1. Mentally constructs test scenarios and edge cases (INTERNAL reasoning) + * 2. Uses those mental models to EVALUATE if the implementation is complete + * 3. Checks if changes might break other parts of the application + * 4. Reports FINDINGS, not suggestions for tests + * + * The test scenarios are the agent's internal thought process - like how a + * senior dev thinks "what about when X happens?" while reviewing code. + * The OUTPUT is the conclusion: "This doesn't handle X" or "X case is covered". + */ + +import { ChatPromptTemplate } from '@langchain/core/prompts'; +import { StructuredOutputParser } from '@langchain/core/output_parsers'; +import { z } from 'zod'; +import { IssueTicket } from '../types/issue-tracker.types.js'; +import { BaseLanguageModel } from '@langchain/core/language_models/base'; +import { AnalysisPrompt } from '../types/agent.types.js'; + +// ========== Execution Modes ========== + +/** + * Peer Review Execution Mode + * - EXECUTE: Execute prompts with LLM (CLI mode with API key) + * - PROMPT_ONLY: Return prompts for calling LLM to execute (MCP mode, no API key) + */ +export enum PeerReviewMode { + EXECUTE = 'execute', + PROMPT_ONLY = 'prompt_only', +} + +/** + * Result when in PROMPT_ONLY mode (MCP) + */ +export interface PromptOnlyResult { + mode: 'prompt_only'; + context: JiraSubAgentContext; + prompts: AnalysisPrompt[]; + instructions: string; +} + +// ========== Output Schemas ========== + +const TicketQualitySchema = z.object({ + overallScore: z.number().min(0).max(100).describe('Overall ticket quality score'), + dimensions: z.object({ + descriptionClarity: z.number().min(0).max(100), + acceptanceCriteriaQuality: z.number().min(0).max(100), + testabilityScore: z.number().min(0).max(100), + scopeDefinition: z.number().min(0).max(100), + technicalContext: z.number().min(0).max(100), + visualDocumentation: z.number().min(0).max(100), + completeness: z.number().min(0).max(100), + }), + feedback: z.object({ + strengths: z.array(z.string()), + weaknesses: z.array(z.string()), + suggestions: z.array(z.string()), + }), + tier: z.enum(['excellent', 'good', 'adequate', 'poor', 'insufficient']), + reviewable: z.boolean(), + reviewabilityReason: z.string(), +}); + +/** + * Acceptance Criteria Validation - focuses on what IS and ISN'T covered + * + * IMPORTANT: The agent DERIVES its own acceptance criteria by analyzing: + * - The full ticket description + * - Any explicit AC field (if present, but don't rely on it) + * - The ticket type (bug vs feature has different expectations) + * - Technical context and constraints mentioned + * + * Like a senior dev who reads the whole ticket and thinks: + * "To implement this properly, I'd need to: 1) do X, 2) handle Y, 3) ensure Z" + */ +const AcceptanceCriteriaValidationSchema = z.object({ + // The agent's derived understanding of what needs to be implemented + derivedRequirements: z.array( + z.object({ + id: z.string(), + requirement: z.string().describe('What the agent derived needs to be done'), + source: z.enum(['description', 'explicit_ac', 'implied', 'ticket_type', 'technical_context']) + .describe('Where this requirement was derived from'), + importance: z.enum(['essential', 'expected', 'nice_to_have']), + }) + ).describe('Requirements derived by analyzing the full ticket, not just AC field'), + + // Analysis of each derived requirement against the PR + criteriaAnalysis: z.array( + z.object({ + criteriaId: z.string().optional(), + criteriaText: z.string(), + status: z.enum(['met', 'unmet', 'partial', 'unclear']), + confidence: z.number().min(0).max(100), + evidence: z.array(z.string()).describe('Code evidence showing coverage or lack thereof'), + explanation: z.string().describe('Why this criteria is/isnt met'), + relatedFiles: z.array(z.string()), + }) + ), + compliancePercentage: z.number().min(0).max(100), + gaps: z.array( + z.object({ + criteriaText: z.string(), + gapDescription: z.string().describe('What specific functionality is missing'), + severity: z.enum(['critical', 'major', 'minor']), + impact: z.string().describe('What will happen if this gap is not addressed'), + }) + ), + // Internal reasoning exposed as findings, not suggestions + missingBehaviors: z.array(z.string()).describe('Behaviors that should exist but dont'), + partialImplementations: z.array(z.string()).describe('Features that are started but incomplete'), +}); + +/** + * Peer Review Analysis - the senior developer's verdict + */ +const PeerReviewAnalysisSchema = z.object({ + implementationCompleteness: z.number().min(0).max(100), + qualityScore: z.number().min(0).max(100), + readyForReview: z.boolean(), + + // Critical findings that block merge + blockers: z.array( + z.object({ + issue: z.string(), + reason: z.string(), + location: z.string().optional().describe('File or component affected'), + }) + ), + + // Important issues that should be fixed + warnings: z.array( + z.object({ + issue: z.string(), + reason: z.string(), + location: z.string().optional(), + }) + ), + + // Nice-to-have improvements + recommendations: z.array(z.string()), + + // Scope analysis + scopeAnalysis: z.object({ + inScope: z.array(z.string()), + outOfScope: z.array(z.string()), + scopeCreepRisk: z.boolean(), + scopeCreepDetails: z.string().optional(), + }), + + // Potential regression analysis - what might break + regressionRisks: z.array( + z.object({ + risk: z.string().describe('What could break'), + affectedArea: z.string().describe('Part of the app that might be affected'), + likelihood: z.enum(['high', 'medium', 'low']), + reasoning: z.string().describe('Why this might happen'), + }) + ), + + // Uncovered scenarios identified during review (findings, not suggestions) + uncoveredScenarios: z.array( + z.object({ + scenario: z.string().describe('A scenario that isnt handled'), + impact: z.enum(['critical', 'major', 'minor']), + relatedCriteria: z.string().optional(), + }) + ), + + // Final verdict + verdict: z.object({ + summary: z.string().describe('One paragraph summary of the review'), + recommendation: z.enum(['approve', 'request_changes', 'needs_discussion']), + confidenceLevel: z.number().min(0).max(100), + }), +}); + +// ========== Types ========== + +export type TicketQualityRating = z.infer; +export type AcceptanceCriteriaValidation = z.infer; +export type PeerReviewAnalysis = z.infer; + +export interface JiraSubAgentResult { + ticketQuality: TicketQualityRating; + acValidation?: AcceptanceCriteriaValidation; + peerReview: PeerReviewAnalysis; +} + +export interface JiraSubAgentContext { + ticket: IssueTicket; + prTitle: string; + prDescription?: string; + diff: string; + files: Array<{ + path: string; + additions: number; + deletions: number; + status: string; + }>; + prSummary?: string; + prRisks?: string[]; +} + +// ========== Prompts ========== + +const TICKET_QUALITY_PROMPT = `You are an expert at evaluating Jira tickets and user stories. +Analyze the following ticket and rate its quality based on industry best practices. + +TICKET INFORMATION: +Key: {ticketKey} +Type: {ticketType} +Title: {ticketTitle} +Description: +{ticketDescription} + +Acceptance Criteria: +{acceptanceCriteria} + +Test Scenarios Defined: {testScenarios} +Has Screenshots/Mockups: {hasScreenshots} +Has Diagrams: {hasDiagrams} +Story Points: {storyPoints} +Labels: {labels} +Components: {components} + +EVALUATION CRITERIA: +1. Description Clarity (0-100): Is the description clear, complete, and unambiguous? +2. Acceptance Criteria Quality (0-100): Are ACs specific, measurable, achievable, and testable (SMART)? +3. Testability Score (0-100): Can this ticket be tested? Are expected behaviors clear? +4. Scope Definition (0-100): Is the scope well-defined and bounded? No scope creep potential? +5. Technical Context (0-100): Are technical requirements, constraints, and dependencies clear? +6. Visual Documentation (0-100): Are there screenshots, mockups, or diagrams where needed? +7. Completeness (0-100): Overall ticket completeness - nothing critical missing? + +QUALITY TIERS: +- excellent (85-100): Exemplary ticket, can be implemented with high confidence +- good (70-84): Well-written ticket with minor gaps +- adequate (50-69): Passable but has notable gaps that may cause issues +- poor (25-49): Significant issues, needs improvement before implementation +- insufficient (0-24): Cannot be implemented reliably, needs major rework + +REVIEWABILITY: +A ticket is "reviewable" if there's enough information to meaningfully derive what needs +to be implemented. This does NOT require an explicit acceptance criteria field! + +A ticket is REVIEWABLE if: +- The description explains what needs to be done (even briefly) +- The title + type give enough context to understand the goal +- A senior developer could reasonably derive requirements from it + +A ticket is NOT REVIEWABLE if: +- It's just a title with no description (e.g., "Fix bug" with nothing else) +- It's too vague to derive any concrete requirements +- There's literally not enough info to know what "done" looks like + +Remember: Many good tickets have detailed descriptions but empty AC fields. +The key is whether YOU can derive what needs to be built. + +{format_instructions}`; + +const AC_VALIDATION_PROMPT = `You are a SENIOR DEVELOPER with deep knowledge of this codebase reviewing a PR. + +Your task: Understand what this ticket requires, then evaluate if the PR implements it correctly. + +CRITICAL: DO NOT just rely on the "Acceptance Criteria" field. Many tickets have empty AC or +poorly written AC. You must DERIVE your own understanding of what needs to be done by reading: +- The full description +- The ticket type (bug fix has different needs than a feature) +- Any technical context mentioned +- The implicit requirements (what any experienced dev would know is needed) + +Think like an experienced dev who reads a ticket and thinks: +"Okay, to implement this properly I need to: handle X, add Y, make sure Z works..." + +JIRA TICKET: +Key: {ticketKey} +Type: {ticketType} +Title: {ticketTitle} + +FULL DESCRIPTION (analyze this carefully): +{ticketDescription} + +EXPLICIT ACCEPTANCE CRITERIA (may be empty or incomplete - don't rely solely on this): +{acceptanceCriteria} + +PR INFORMATION: +Title: {prTitle} +Description: {prDescription} + +FILES CHANGED: +{filesChanged} + +CODE DIFF: +{diff} + +PREVIOUS PR ANALYSIS SUMMARY: +{prSummary} + +YOUR TASK: + +1. DERIVE REQUIREMENTS: + First, read the entire ticket and derive what actually needs to be implemented. + For each requirement you identify, note: + - What the requirement is + - Where you derived it from (description, explicit AC, implied by ticket type, technical context) + - How essential it is (essential, expected, nice-to-have) + + Don't just copy the AC field - THINK about what's really needed. + A ticket saying "Add login button" implies: the button should be visible, clickable, + trigger auth flow, handle errors, etc. + +2. VALIDATE EACH REQUIREMENT: + For each derived requirement: + - Is it MET, UNMET, PARTIAL, or UNCLEAR in the code? + - Provide CODE EVIDENCE + - Explain your reasoning + +3. IDENTIFY GAPS: + What's missing? What behaviors should exist but don't? + Think through scenarios: "What if the user does X?" "What about error case Y?" + +Report FINDINGS, not suggestions. Like a senior dev saying: +"This doesn't handle the case when the user is logged out" + +{format_instructions}`; + +const PEER_REVIEW_PROMPT = `You are a SENIOR DEVELOPER doing a thorough peer review. + +You've been with this team for years. You know where the bodies are buried. +You think about: +- Does this actually solve the problem in the ticket? +- What might this break in other parts of the app? +- Are there scenarios the developer didn't consider? +- Is this ready for production? + +JIRA TICKET: +Key: {ticketKey} +Type: {ticketType} +Title: {ticketTitle} +Description: {ticketDescription} +Acceptance Criteria: {acceptanceCriteria} + +PR INFORMATION: +Title: {prTitle} +Description: {prDescription} + +FILES CHANGED: +{filesChanged} + +DIFF SUMMARY: +{diff} + +EXISTING PR ANALYSIS: +Summary: {prSummary} +Risks Identified: {prRisks} + +TICKET QUALITY ASSESSMENT: +Overall Score: {ticketQualityScore}/100 +Reviewable: {isReviewable} + +AC VALIDATION RESULTS: +Compliance: {acCompliancePercentage}% +Gaps Found: {gapsFound} + +YOUR PEER REVIEW TASK: + +1. IMPLEMENTATION COMPLETENESS (0-100): + Does this PR fully implement what the ticket asks for? + +2. QUALITY SCORE (0-100): + Code quality + requirements adherence combined + +3. READY FOR REVIEW: + Would you approve this or request changes? + +4. BLOCKERS: + Critical issues - things that MUST be fixed before merge + (missing functionality, bugs, security issues) + +5. WARNINGS: + Important issues - things that SHOULD be fixed + (edge cases not handled, potential bugs) + +6. RECOMMENDATIONS: + Nice-to-haves for improvement + +7. SCOPE ANALYSIS: + - What's in scope vs out of scope? + - Is there scope creep? + +8. REGRESSION RISKS: + Think: "What else in the app might this break?" + - Consider dependencies, shared code, side effects + - Think about how this interacts with existing features + +9. UNCOVERED SCENARIOS: + As a senior dev, you mentally run through scenarios: + - "What if the user does X?" + - "What about when Y is null?" + - "What happens during Z error condition?" + + Report which scenarios you identified that AREN'T handled. + Don't suggest tests - just flag what's missing. + +10. FINAL VERDICT: + Give your honest assessment: + - APPROVE: Ready to merge (maybe minor nits) + - REQUEST_CHANGES: Needs work before merge + - NEEDS_DISCUSSION: Architectural concerns to discuss + +{format_instructions}`; + +// ========== Agent Class ========== + +export class JiraSubAgent { + private mode: PeerReviewMode; + private llm?: BaseLanguageModel; + + constructor(mode: PeerReviewMode = PeerReviewMode.EXECUTE, llm?: BaseLanguageModel) { + this.mode = mode; + this.llm = llm; + + // Validate: EXECUTE mode requires LLM + if (mode === PeerReviewMode.EXECUTE && !llm) { + throw new Error('JiraSubAgent: LLM is required when mode is EXECUTE'); + } + } + + /** + * Analyze a ticket and PR, providing comprehensive peer review + * Returns either executed results (EXECUTE mode) or prompts (PROMPT_ONLY mode) + */ + async analyze(context: JiraSubAgentContext): Promise { + if (this.mode === PeerReviewMode.PROMPT_ONLY) { + return this.buildPrompts(context); + } else { + return this.executeAnalysis(context); + } + } + + /** + * Build prompts without executing (MCP mode) + */ + private buildPrompts(context: JiraSubAgentContext): PromptOnlyResult { + const prompts: AnalysisPrompt[] = []; + + // Step 1: Build ticket quality prompt + prompts.push(this.buildTicketQualityPrompt(context.ticket)); + + // Step 2: Build AC validation prompt (always - agent derives requirements) + prompts.push(this.buildACValidationPrompt(context)); + + // Step 3: Build peer review prompt + // Note: In PROMPT_ONLY mode, we don't know ticketQuality yet, + // so we include it as a dependency instruction + prompts.push(this.buildPeerReviewPrompt(context)); + + return { + mode: 'prompt_only', + context, + prompts, + instructions: + 'Execute these prompts sequentially. ' + + 'Pass the output of ticketQuality to peerReview as ticketQualityScore. ' + + 'Parse each response according to the provided schema.' + }; + } + + /** + * Execute analysis with LLM (CLI mode) + */ + private async executeAnalysis(context: JiraSubAgentContext): Promise { + // Step 1: Rate ticket quality + const ticketQuality = await this.rateTicketQuality(context.ticket); + + // Step 2: Derive requirements and validate against PR + // NOTE: We analyze even if there's no explicit AC field - the agent derives + // requirements from the full ticket (description, title, type, context) + let acValidation: AcceptanceCriteriaValidation | undefined; + if (ticketQuality.reviewable) { + // The agent will derive its own requirements from the ticket + // Don't skip just because acceptanceCriteriaList is empty + acValidation = await this.validateAcceptanceCriteria(context); + } + + // Step 3: Generate peer review analysis + const peerReview = await this.generatePeerReview(context, ticketQuality, acValidation); + + return { + ticketQuality, + acValidation, + peerReview, + }; + } + + /** + * Build ticket quality prompt (PROMPT_ONLY mode) + */ + private buildTicketQualityPrompt(ticket: IssueTicket): AnalysisPrompt { + const parser = StructuredOutputParser.fromZodSchema(TicketQualitySchema); + + const inputs = { + ticketKey: ticket.key, + ticketType: ticket.type, + ticketTitle: ticket.title, + ticketDescription: ticket.description || 'No description provided', + acceptanceCriteria: ticket.acceptanceCriteria || + ticket.acceptanceCriteriaList?.join('\n') || + 'No acceptance criteria defined', + testScenarios: ticket.testScenarios?.join(', ') || 'None defined', + hasScreenshots: ticket.hasScreenshots ? 'Yes' : 'No', + hasDiagrams: ticket.hasDiagrams ? 'Yes' : 'No', + storyPoints: ticket.storyPoints?.toString() || 'Not estimated', + labels: ticket.labels.join(', ') || 'None', + components: ticket.components.join(', ') || 'None', + format_instructions: parser.getFormatInstructions(), + }; + + // Fill in the template + let prompt = TICKET_QUALITY_PROMPT; + for (const [key, value] of Object.entries(inputs)) { + prompt = prompt.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value)); + } + + return { + step: 'ticketQuality', + prompt, + schema: TicketQualitySchema, + formatInstructions: parser.getFormatInstructions(), + inputs, + instructions: 'Analyze the ticket quality and return a JSON object matching the schema', + }; + } + + /** + * Build AC validation prompt (PROMPT_ONLY mode) + */ + private buildACValidationPrompt(context: JiraSubAgentContext): AnalysisPrompt { + const parser = StructuredOutputParser.fromZodSchema(AcceptanceCriteriaValidationSchema); + + // Format acceptance criteria with IDs + const acList = context.ticket.acceptanceCriteriaList || []; + const formattedAC = acList + .map((ac, i) => `AC-${i + 1}: ${ac}`) + .join('\n'); + + // Format files changed + const filesChanged = context.files + .map((f) => `${f.path} (+${f.additions}/-${f.deletions}) [${f.status}]`) + .join('\n'); + + // Truncate diff if too long + const maxDiffLength = 15000; + const truncatedDiff = + context.diff.length > maxDiffLength + ? context.diff.substring(0, maxDiffLength) + '\n... [diff truncated]' + : context.diff; + + const inputs = { + ticketKey: context.ticket.key, + ticketType: context.ticket.type, + ticketTitle: context.ticket.title, + ticketDescription: context.ticket.description?.substring(0, 2000) || 'No description', + acceptanceCriteria: formattedAC || 'No acceptance criteria defined', + prTitle: context.prTitle, + prDescription: context.prDescription || 'No description', + filesChanged, + diff: truncatedDiff, + prSummary: context.prSummary || 'No summary available', + format_instructions: parser.getFormatInstructions(), + }; + + // Fill in the template + let prompt = AC_VALIDATION_PROMPT; + for (const [key, value] of Object.entries(inputs)) { + prompt = prompt.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value)); + } + + return { + step: 'acValidation', + prompt, + schema: AcceptanceCriteriaValidationSchema, + formatInstructions: parser.getFormatInstructions(), + inputs, + instructions: 'Validate acceptance criteria coverage and return a JSON object matching the schema', + }; + } + + /** + * Build peer review prompt (PROMPT_ONLY mode) + */ + private buildPeerReviewPrompt(context: JiraSubAgentContext): AnalysisPrompt { + const parser = StructuredOutputParser.fromZodSchema(PeerReviewAnalysisSchema); + + // Format files changed + const filesChanged = context.files + .map((f) => `${f.path} (+${f.additions}/-${f.deletions}) [${f.status}]`) + .join('\n'); + + // Truncate diff if too long + const maxDiffLength = 10000; + const truncatedDiff = + context.diff.length > maxDiffLength + ? context.diff.substring(0, maxDiffLength) + '\n... [diff truncated]' + : context.diff; + + const inputs = { + ticketKey: context.ticket.key, + ticketType: context.ticket.type, + ticketTitle: context.ticket.title, + ticketDescription: context.ticket.description?.substring(0, 2000) || 'No description', + acceptanceCriteria: + context.ticket.acceptanceCriteria || + context.ticket.acceptanceCriteriaList?.join('\n') || + 'None defined', + prTitle: context.prTitle, + prDescription: context.prDescription || 'No description', + filesChanged, + diff: truncatedDiff, + prSummary: context.prSummary || 'No summary available', + prRisks: context.prRisks?.join(', ') || 'None identified', + // Placeholders for ticket quality - will be filled by calling LLM + ticketQualityScore: '{RESULT_FROM_ticketQuality.overallScore}', + isReviewable: '{RESULT_FROM_ticketQuality.reviewable}', + acCompliancePercentage: '{RESULT_FROM_acValidation.compliancePercentage}', + gapsFound: '{RESULT_FROM_acValidation.gaps}', + format_instructions: parser.getFormatInstructions(), + }; + + // Fill in the template + let prompt = PEER_REVIEW_PROMPT; + for (const [key, value] of Object.entries(inputs)) { + prompt = prompt.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value)); + } + + return { + step: 'peerReview', + prompt, + schema: PeerReviewAnalysisSchema, + formatInstructions: parser.getFormatInstructions(), + inputs, + instructions: 'Perform peer review analysis and return a JSON object matching the schema', + }; + } + + /** + * Rate the quality of a Jira ticket (EXECUTE mode) + */ + async rateTicketQuality(ticket: IssueTicket): Promise { + if (!this.llm) { + throw new Error('LLM is required for rateTicketQuality in EXECUTE mode'); + } + + const parser = StructuredOutputParser.fromZodSchema(TicketQualitySchema); + + const prompt = ChatPromptTemplate.fromTemplate(TICKET_QUALITY_PROMPT); + + const chain = prompt.pipe(this.llm); + + const response = await chain.invoke({ + ticketKey: ticket.key, + ticketType: ticket.type, + ticketTitle: ticket.title, + ticketDescription: ticket.description || 'No description provided', + acceptanceCriteria: ticket.acceptanceCriteria || + ticket.acceptanceCriteriaList?.join('\n') || + 'No acceptance criteria defined', + testScenarios: ticket.testScenarios?.join(', ') || 'None defined', + hasScreenshots: ticket.hasScreenshots ? 'Yes' : 'No', + hasDiagrams: ticket.hasDiagrams ? 'Yes' : 'No', + storyPoints: ticket.storyPoints?.toString() || 'Not estimated', + labels: ticket.labels.join(', ') || 'None', + components: ticket.components.join(', ') || 'None', + format_instructions: parser.getFormatInstructions(), + }); + + const content = typeof response === 'string' ? response : response.content?.toString() || ''; + return parser.parse(content); + } + + /** + * Validate acceptance criteria against PR changes + */ + async validateAcceptanceCriteria( + context: JiraSubAgentContext + ): Promise { + if (!this.llm) { + throw new Error('LLM is required for validateAcceptanceCriteria in EXECUTE mode'); + } + + const parser = StructuredOutputParser.fromZodSchema(AcceptanceCriteriaValidationSchema); + + const prompt = ChatPromptTemplate.fromTemplate(AC_VALIDATION_PROMPT); + + const chain = prompt.pipe(this.llm); + + // Format acceptance criteria with IDs + const acList = context.ticket.acceptanceCriteriaList || []; + const formattedAC = acList + .map((ac, i) => `AC-${i + 1}: ${ac}`) + .join('\n'); + + // Format files changed + const filesChanged = context.files + .map((f) => `${f.path} (+${f.additions}/-${f.deletions}) [${f.status}]`) + .join('\n'); + + // Truncate diff if too long + const maxDiffLength = 15000; + const truncatedDiff = + context.diff.length > maxDiffLength + ? context.diff.substring(0, maxDiffLength) + '\n... [diff truncated]' + : context.diff; + + const response = await chain.invoke({ + ticketKey: context.ticket.key, + ticketType: context.ticket.type, + ticketTitle: context.ticket.title, + ticketDescription: context.ticket.description?.substring(0, 2000) || 'No description', + acceptanceCriteria: formattedAC || 'No acceptance criteria defined', + prTitle: context.prTitle, + prDescription: context.prDescription || 'No description', + filesChanged, + diff: truncatedDiff, + prSummary: context.prSummary || 'No summary available', + format_instructions: parser.getFormatInstructions(), + }); + + const content = typeof response === 'string' ? response : response.content?.toString() || ''; + return parser.parse(content); + } + + /** + * Generate comprehensive peer review analysis + */ + async generatePeerReview( + context: JiraSubAgentContext, + ticketQuality: TicketQualityRating, + acValidation?: AcceptanceCriteriaValidation + ): Promise { + if (!this.llm) { + throw new Error('LLM is required for generatePeerReview in EXECUTE mode'); + } + + const parser = StructuredOutputParser.fromZodSchema(PeerReviewAnalysisSchema); + + const prompt = ChatPromptTemplate.fromTemplate(PEER_REVIEW_PROMPT); + + const chain = prompt.pipe(this.llm); + + // Format files changed + const filesChanged = context.files + .map((f) => `${f.path} (+${f.additions}/-${f.deletions}) [${f.status}]`) + .join('\n'); + + // Truncate diff if too long + const maxDiffLength = 10000; + const truncatedDiff = + context.diff.length > maxDiffLength + ? context.diff.substring(0, maxDiffLength) + '\n... [diff truncated]' + : context.diff; + + // Format gaps found + const gapsFound = acValidation?.gaps + .map((g) => `- ${g.criteriaText}: ${g.gapDescription}`) + .join('\n') || 'None identified'; + + const response = await chain.invoke({ + ticketKey: context.ticket.key, + ticketType: context.ticket.type, + ticketTitle: context.ticket.title, + ticketDescription: context.ticket.description?.substring(0, 2000) || 'No description', + acceptanceCriteria: + context.ticket.acceptanceCriteria || + context.ticket.acceptanceCriteriaList?.join('\n') || + 'None defined', + prTitle: context.prTitle, + prDescription: context.prDescription || 'No description', + filesChanged, + diff: truncatedDiff, + prSummary: context.prSummary || 'No summary available', + prRisks: context.prRisks?.join(', ') || 'None identified', + ticketQualityScore: ticketQuality.overallScore, + isReviewable: ticketQuality.reviewable ? 'Yes' : 'No', + acCompliancePercentage: acValidation?.compliancePercentage ?? 'N/A', + gapsFound, + format_instructions: parser.getFormatInstructions(), + }); + + const content = typeof response === 'string' ? response : response.content?.toString() || ''; + return parser.parse(content); + } +} diff --git a/src/agents/pr-analyzer-agent.ts b/src/agents/pr-analyzer-agent.ts index ba70174..91e3bdc 100644 --- a/src/agents/pr-analyzer-agent.ts +++ b/src/agents/pr-analyzer-agent.ts @@ -3,27 +3,53 @@ * LangChain-based agent for intelligent PR analysis */ +import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { BasePRAgentWorkflow } from './base-pr-agent-workflow.js'; -import { AgentContext, AgentResult, AgentMetadata, AnalysisMode } from '../types/agent.types.js'; +import { AgentContext, AgentResult, AgentResultOrPrompts, AgentMetadata, AnalysisMode, ExecutionMode } from '../types/agent.types.js'; import { parseDiff } from '../tools/pr-analysis-tools.js'; import { ProviderFactory, ProviderOptions } from '../providers/index.js'; import { parseAllArchDocs, archDocsExists } from '../utils/arch-docs-parser.js'; import { buildArchDocsContext } from '../utils/arch-docs-rag.js'; +/** + * Extended options that allow passing a pre-configured model + * Used by MCP server to pass its underlying LLM model + */ +export interface PRAnalyzerOptions extends ProviderOptions { + /** Execution mode: EXECUTE (with API key) or PROMPT_ONLY (return prompts) */ + mode?: ExecutionMode; + /** Pre-configured LangChain model (for MCP server pass-through) */ + chatModel?: BaseChatModel; +} + /** * PR Analysis Agent using LangChain and LangGraph */ export class PRAnalyzerAgent extends BasePRAgentWorkflow { - constructor(options: ProviderOptions = {}) { - const model = ProviderFactory.createChatModel({ - provider: options.provider || 'anthropic', - apiKey: options.apiKey, - model: options.model, - temperature: options.temperature ?? 0.2, - maxTokens: options.maxTokens ?? 4000, - }); - - super(model); + constructor(options: PRAnalyzerOptions = {}) { + // Determine execution mode + const mode = options.mode || ExecutionMode.EXECUTE; + + let model: BaseChatModel | undefined; + + // Only create model in EXECUTE mode + if (mode === ExecutionMode.EXECUTE) { + // If a pre-configured BaseChatModel is passed (MCP case), use it directly + if (options.chatModel) { + model = options.chatModel; + } else { + // Otherwise create model via ProviderFactory (CLI/Action case - backward compatible) + model = ProviderFactory.createChatModel({ + provider: options.provider || 'anthropic', + apiKey: options.apiKey, + model: options.model, + temperature: options.temperature ?? 0.2, + maxTokens: options.maxTokens ?? 50000, + }); + } + } + + super(mode, model); } /** @@ -46,19 +72,22 @@ export class PRAnalyzerAgent extends BasePRAgentWorkflow { /** * Analyze a PR with full agent workflow + * Returns either executed results (EXECUTE mode) or prompts (PROMPT_ONLY mode) */ async analyze( diff: string, title?: string, mode?: AnalysisMode, - options?: { - useArchDocs?: boolean; + options?: { + useArchDocs?: boolean; repoPath?: string; + repoOwner?: string; + repoName?: string; language?: string; framework?: string; enableStaticAnalysis?: boolean; } - ): Promise { + ): Promise { // Parse diff into files const files = parseDiff(diff); @@ -78,6 +107,11 @@ export class PRAnalyzerAgent extends BasePRAgentWorkflow { maxCost: 5.0, mode: mode || { summary: true, risks: true, complexity: true }, archDocs: archDocsContext, + config: { + repoPath: options?.repoPath, + repoOwner: options?.repoOwner, + repoName: options?.repoName, + }, language: options?.language, framework: options?.framework, enableStaticAnalysis: options?.enableStaticAnalysis !== false, // Default to true @@ -95,16 +129,16 @@ export class PRAnalyzerAgent extends BasePRAgentWorkflow { * Quick analysis without refinement */ async quickAnalyze( - diff: string, - title?: string, - options?: { - useArchDocs?: boolean; + diff: string, + title?: string, + options?: { + useArchDocs?: boolean; repoPath?: string; language?: string; framework?: string; enableStaticAnalysis?: boolean; } - ): Promise { + ): Promise { const files = parseDiff(diff); // Build arch-docs context if enabled @@ -135,7 +169,7 @@ export class PRAnalyzerAgent extends BasePRAgentWorkflow { /** * Analyze specific files only */ - async analyzeFiles(diff: string, filePaths: string[], options?: { useArchDocs?: boolean; repoPath?: string }): Promise { + async analyzeFiles(diff: string, filePaths: string[], options?: { useArchDocs?: boolean; repoPath?: string }): Promise { const allFiles = parseDiff(diff); const files = allFiles.filter(f => filePaths.includes(f.path)); @@ -174,7 +208,7 @@ export class PRAnalyzerAgent extends BasePRAgentWorkflow { const baseTokens = 2000; const diffTokens = Math.ceil(context.diff.length / 4); // ~4 chars per token const filesTokens = context.files.length * 100; - + return baseTokens + diffTokens + filesTokens; } } @@ -182,7 +216,7 @@ export class PRAnalyzerAgent extends BasePRAgentWorkflow { /** * Factory function to create PR analyzer agent */ -export function createPRAnalyzerAgent(options: ProviderOptions = {}): PRAnalyzerAgent { +export function createPRAnalyzerAgent(options: PRAnalyzerOptions = {}): PRAnalyzerAgent { return new PRAnalyzerAgent(options); } @@ -191,8 +225,8 @@ export function createPRAnalyzerAgent(options: ProviderOptions = {}): PRAnalyzer * @deprecated Use PRAnalyzerAgent constructor with ProviderOptions instead */ export function createPRAnalyzerAgentLegacy(apiKey: string, modelName?: string): PRAnalyzerAgent { - return new PRAnalyzerAgent({ - apiKey, + return new PRAnalyzerAgent({ + apiKey, model: modelName, provider: 'anthropic' }); diff --git a/src/cli/commands/analyze.command.ts b/src/cli/commands/analyze.command.ts index 37b75b8..7f50838 100644 --- a/src/cli/commands/analyze.command.ts +++ b/src/cli/commands/analyze.command.ts @@ -2,13 +2,27 @@ import * as fs from 'fs'; import { execSync } from 'child_process'; import chalk from 'chalk'; import ora from 'ora'; +import open from 'open'; import { PRAnalyzerAgent } from '../../agents/pr-analyzer-agent.js'; import { loadUserConfig, getApiKey } from '../utils/config-loader.js'; import { archDocsExists } from '../../utils/arch-docs-parser.js'; import { resolveDefaultBranch } from '../../utils/branch-resolver.js'; import { ConfigurationError, GitHubAPIError, GitError } from '../../utils/errors.js'; + +import { + createPeerReviewIntegration, + formatPeerReviewOutput, + PeerReviewMode, + type PeerReviewResult, +} from '../../issue-tracker/index.js'; +import { ExecutionMode, type AgentResult } from '../../types/agent.types.js'; +import { ProviderFactory, type SupportedProvider } from '../../providers/index.js'; import { Fix } from '../../types/agent.types.js'; +import { saveAnalysis } from '../../db/index.js'; +import { getCoverageAnalysis, formatCoverageAnalysis, runEslintAnalysis, formatStaticAnalysis } from '../../tools/index.js'; + + interface AnalyzeOptions { diff?: string; file?: string; @@ -25,6 +39,11 @@ interface AnalyzeOptions { verbose?: boolean; maxCost?: number; archDocs?: boolean; + peerReview?: boolean; // Enable Jira peer review integration + showClassification?: boolean; // Show project type classification + scanCoverage?: boolean; // Run coverage analysis and suggest tests + showCoverage?: boolean; // Display coverage metrics + showStaticAnalysis?: boolean; // Run and show ESLint static analysis } interface AnalysisMode { @@ -216,6 +235,59 @@ async function getPRTitle(): Promise { } } +/** + * Get repository info from git remote URL + */ +function getRepoInfo(): { owner: string; name: string } { + try { + const remoteUrl = execSync('git remote get-url origin', { encoding: 'utf-8' }).trim(); + // Handle SSH format: git@github.com:owner/repo.git + // Handle HTTPS format: https://github.com/owner/repo.git + const sshMatch = remoteUrl.match(/git@[^:]+:([^/]+)\/(.+?)(?:\.git)?$/); + if (sshMatch) { + return { owner: sshMatch[1], name: sshMatch[2] }; + } + const httpsMatch = remoteUrl.match(/https?:\/\/[^/]+\/([^/]+)\/(.+?)(?:\.git)?$/); + if (httpsMatch) { + return { owner: httpsMatch[1], name: httpsMatch[2] }; + } + // Fallback to current directory name + return { owner: 'local', name: process.cwd().split(/[\\/]/).pop() || 'unknown' }; + } catch { + return { owner: 'local', name: process.cwd().split(/[\\/]/).pop() || 'unknown' }; + } +} + +/** + * Get git author from config + */ +function getGitAuthor(): string { + try { + return execSync('git config user.name', { encoding: 'utf-8' }).trim() || 'unknown'; + } catch { + return 'unknown'; + } +} + +/** + * Extract PR number from branch name if it follows common patterns + * e.g., feature/PR-123, fix-123, 123-feature + */ +function extractPRNumber(branchName?: string, title?: string): number { + // Try to extract from branch name + if (branchName) { + const branchMatch = branchName.match(/(?:PR-?|#)?(\d+)/i); + if (branchMatch) return parseInt(branchMatch[1], 10); + } + // Try to extract from title + if (title) { + const titleMatch = title.match(/#(\d+)/); + if (titleMatch) return parseInt(titleMatch[1], 10); + } + // Generate a timestamp-based "PR number" for local analysis + return Math.floor(Date.now() / 1000) % 100000; +} + /** * Estimate diff size in tokens */ @@ -262,15 +334,16 @@ export async function analyzePR(options: AnalyzeOptions = {}): Promise { } throw error; } - + // Get provider and API key from config or environment if (options.verbose) { console.log(chalk.gray(` Debug: options.provider: ${options.provider || 'undefined'}`)); console.log(chalk.gray(` Debug: config.ai?.provider: ${config.ai?.provider || 'undefined'}`)); } - const provider = (options.provider || config.ai?.provider || 'anthropic').toLowerCase() as 'anthropic' | 'openai' | 'google'; + const provider = (options.provider || config.ai?.provider || 'anthropic').toLowerCase() as SupportedProvider; const apiKey = getApiKey(provider, config); - + const model = options.model || config.ai?.model; + if (!apiKey) { spinner.fail('No API key found'); console.error(chalk.yellow('💡 Please set it in one of these ways:')); @@ -279,9 +352,13 @@ export async function analyzePR(options: AnalyzeOptions = {}): Promise { console.error(chalk.gray(' - Anthropic (Claude): export ANTHROPIC_API_KEY="your-api-key"')); console.error(chalk.gray(' - OpenAI (GPT): export OPENAI_API_KEY="your-api-key"')); console.error(chalk.gray(' - Google (Gemini): export GOOGLE_API_KEY="your-api-key"')); + console.error(chalk.gray(' - Zhipu (GLM): export ZHIPU_API_KEY="your-api-key"')); + if (options.verbose) { + console.error(chalk.gray(` Debug: Provider=${provider}, Config apiKeys=${JSON.stringify(config.apiKeys || {})}`)); + } process.exit(1); } - + spinner.succeed(`Using AI provider: ${provider}`); // Resolve default branch if needed @@ -294,13 +371,13 @@ export async function analyzePR(options: AnalyzeOptions = {}): Promise { githubToken: process.env.GITHUB_TOKEN, fallbackToGit: true, }); - + defaultBranch = branchResult.branch; - + if (branchResult.warning && options.verbose) { console.log(chalk.yellow(`\n⚠️ ${branchResult.warning}`)); } - + if (options.verbose) { console.log(chalk.gray(` Using branch: ${defaultBranch} (source: ${branchResult.source})`)); } @@ -391,32 +468,243 @@ export async function analyzePR(options: AnalyzeOptions = {}): Promise { // Check for arch-docs const useArchDocs = options.archDocs !== false; // Default to true if not specified const hasArchDocs = archDocsExists(); - + if (useArchDocs && hasArchDocs) { console.log(chalk.cyan('📚 Architecture documentation detected - including in analysis\n')); } else if (options.archDocs && !hasArchDocs) { console.log(chalk.yellow('⚠️ --arch-docs flag specified but no .arch-docs folder found\n')); } - const model = options.model || config.ai?.model; + // Get repo info early so we can pass it to the agent for caching + const repoInfo = getRepoInfo(); + const agent = new PRAnalyzerAgent({ - provider: provider as any, + mode: ExecutionMode.EXECUTE, // CLI always executes with API key + provider: provider, apiKey, model, }); - const result = await agent.analyze(diff, title, mode, { + const analysisResult = await agent.analyze(diff, title, mode, { useArchDocs: useArchDocs && hasArchDocs, repoPath: process.cwd(), + repoOwner: repoInfo.owner, + repoName: repoInfo.name, language: config.analysis?.language, framework: config.analysis?.framework, enableStaticAnalysis: config.analysis?.enableStaticAnalysis !== false, }); + // Type guard: CLI always uses EXECUTE mode, so result is always AgentResult + if (analysisResult.mode === 'prompt_only') { + throw new Error('Unexpected prompt-only result in CLI EXECUTE mode'); + } + const result = analysisResult as AgentResult; + // Display results - displayAgentResults(result, mode, options.verbose || false); + displayAgentResults(result, mode, options.verbose || false, options.showClassification || false); + + // Run and display coverage analysis if requested + if (options.scanCoverage || options.showCoverage) { + console.log(chalk.gray('\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + const coverageAnalysis = getCoverageAnalysis(process.cwd()); + if (coverageAnalysis.hasReport) { + console.log('\\n' + formatCoverageAnalysis(coverageAnalysis)); + } else { + console.log(chalk.yellow('\\n📊 No coverage report found.')); + console.log(chalk.gray(' Run: npm test -- --coverage to generate one.')); + } + } + + // Run and display ESLint static analysis if requested + if (options.showStaticAnalysis) { + console.log(chalk.gray('\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.cyan('\\n🔬 Running static analysis...')); + const staticAnalysis = await runEslintAnalysis(process.cwd()); + console.log('\\n' + formatStaticAnalysis(staticAnalysis)); + } + + // Save analysis results to local database for dashboard + try { + const repoInfo = getRepoInfo(); + const author = getGitAuthor(); + let branchName: string | undefined; + try { + branchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim(); + } catch { + // ignore + } + const prNumber = extractPRNumber(branchName, title); + + // Calculate overall complexity from file analyses + let overallComplexity = 1; + if (result.fileAnalyses && result.fileAnalyses.size > 0) { + const complexities = Array.from(result.fileAnalyses.values()).map((f: any) => f.complexity || 1); + overallComplexity = Math.round(complexities.reduce((a: number, b: number) => a + b, 0) / complexities.length); + } + + // Calculate DevOps cost if estimates available + const devOpsCostMonthly = result.devOpsCostEstimates?.reduce( + (sum: number, e: any) => sum + (e.estimatedNewCost || 0), 0 + ) || 0; + const devOpsResources = result.devOpsCostEstimates + ? JSON.stringify(result.devOpsCostEstimates) + : undefined; + + saveAnalysis({ + pr_number: prNumber, + repo_owner: repoInfo.owner, + repo_name: repoInfo.name, + author: author, + title: title || 'Untitled Analysis', + complexity: overallComplexity, + risks_count: result.fixes?.filter((f: Fix) => f.severity === 'critical' || f.severity === 'warning').length || 0, + risks: JSON.stringify(result.fixes?.filter((f: Fix) => f.severity === 'critical' || f.severity === 'warning').map((f: Fix) => f.comment) || []), + recommendations: JSON.stringify(result.recommendations || []), + // DevOps/Infrastructure cost tracking (v0.2.0) + devops_cost_monthly: devOpsCostMonthly > 0 ? devOpsCostMonthly : undefined, + devops_resources: devOpsResources, + has_test_suggestions: (result.testSuggestions?.length ?? 0) > 0 ? 1 : 0, + test_suggestions_count: result.testSuggestions?.length ?? 0, + coverage_percentage: result.coverageReport?.overallPercentage, + // Project classification cache (v0.3.0) + project_classification: result.projectClassification, + }); + + if (options.verbose) { + console.log(chalk.gray(` Analysis saved to local database (PR #${prNumber})`)); + } + } catch (saveError: any) { + if (options.verbose) { + console.log(chalk.yellow(` Warning: Could not save to local database: ${saveError.message}`)); + } + } + + // Run Peer Review if enabled (via flag or config) + const peerReviewEnabled = options.peerReview ?? config.peerReview?.enabled ?? false; + if (options.verbose) { + console.log(chalk.gray(`\n Debug: peerReviewEnabled=${peerReviewEnabled}, options.peerReview=${options.peerReview}, config.peerReview?.enabled=${config.peerReview?.enabled}`)); + } + if (peerReviewEnabled) { + // Pass the same provider config to peer review so it uses the same LLM + const peerReviewResult = await runPeerReview(config, diff, title, result, options.verbose || false, { + provider, + apiKey, + model, + }); + + // Save peer review results to database for dashboard + if (peerReviewResult && peerReviewResult.enabled && peerReviewResult.analysis) { + try { + const repoInfo = getRepoInfo(); + const author = getGitAuthor(); + let branchName: string | undefined; + try { + branchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim(); + } catch { + // ignore + } + const prNumber = extractPRNumber(branchName, title); + + // Calculate overall complexity from file analyses + let overallComplexity = 1; + if (result.fileAnalyses && result.fileAnalyses.size > 0) { + const complexities = Array.from(result.fileAnalyses.values()).map((f: any) => f.complexity || 1); + overallComplexity = Math.round(complexities.reduce((a: number, b: number) => a + b, 0) / complexities.length); + } + + // Calculate DevOps cost if estimates available + const devOpsCostMonthly = result.devOpsCostEstimates?.reduce( + (sum: number, e: any) => sum + (e.estimatedNewCost || 0), 0 + ) || 0; + const devOpsResources = result.devOpsCostEstimates + ? JSON.stringify(result.devOpsCostEstimates) + : undefined; + + // Extract peer review data + const analysis = peerReviewResult.analysis; + const primaryTicket = peerReviewResult.primaryTicket; + + // Determine verdict from peerReview analysis + let verdict = 'needs_discussion'; + if (analysis.peerReview.readyForReview && analysis.peerReview.blockers.length === 0) { + verdict = 'approve'; + } else if (analysis.peerReview.blockers.length > 0) { + verdict = 'request_changes'; + } + + saveAnalysis({ + pr_number: prNumber, + repo_owner: repoInfo.owner, + repo_name: repoInfo.name, + author: author, + title: title || 'Untitled Analysis', + complexity: overallComplexity, + risks_count: result.fixes?.filter((f: Fix) => f.severity === 'critical' || f.severity === 'warning').length || 0, + risks: JSON.stringify(result.fixes?.filter((f: Fix) => f.severity === 'critical' || f.severity === 'warning').map((f: Fix) => f.comment) || []), + recommendations: JSON.stringify(result.recommendations || []), + // DevOps/Infrastructure cost tracking (v0.2.0) + devops_cost_monthly: devOpsCostMonthly > 0 ? devOpsCostMonthly : undefined, + devops_resources: devOpsResources, + has_test_suggestions: (result.testSuggestions?.length ?? 0) > 0 ? 1 : 0, + test_suggestions_count: result.testSuggestions?.length ?? 0, + coverage_percentage: result.coverageReport?.overallPercentage, + // Peer Review data (v0.3.0) + peer_review_enabled: 1, + ticket_key: primaryTicket?.key, + ticket_quality_score: analysis.ticketQuality.overallScore, + ticket_quality_tier: analysis.ticketQuality.tier, + ac_compliance_percentage: analysis.acValidation?.compliancePercentage, + ac_requirements_met: analysis.acValidation?.criteriaAnalysis?.filter(c => c.status === 'met').length, + ac_requirements_total: analysis.acValidation?.criteriaAnalysis?.length, + peer_review_verdict: verdict, + peer_review_blockers: JSON.stringify(analysis.peerReview.blockers), + peer_review_warnings: JSON.stringify(analysis.peerReview.warnings), + implementation_completeness: analysis.peerReview.implementationCompleteness, + quality_score: analysis.peerReview.qualityScore, + }); + + if (options.verbose) { + console.log(chalk.gray(` Peer review results saved to database (PR #${prNumber}, ticket: ${primaryTicket?.key || 'N/A'})`)); + } + } catch (saveError: any) { + if (options.verbose) { + console.log(chalk.yellow(` Warning: Could not save peer review to database: ${saveError.message}`)); + } + } + } + } + + // Auto-start and open dashboard after analysis completes + try { + const dashboardUrl = 'http://localhost:3000'; + console.log(chalk.gray(`\n📊 Starting dashboard...`)); + + // Start dashboard server in background + const { spawn } = await import('child_process'); + const dashboardProcess = spawn(process.execPath, [ + process.argv[1], // Path to CLI entry point + 'dashboard' + ], { + detached: true, + stdio: 'ignore' + }); + dashboardProcess.unref(); + + // Wait a moment for server to start + await new Promise(resolve => setTimeout(resolve, 2000)); + + console.log(chalk.green(`✓ Dashboard running at ${dashboardUrl}`)); + console.log(chalk.gray(` Opening browser...`)); + await open(dashboardUrl); + } catch (openError: any) { + if (options.verbose) { + console.log(chalk.yellow(` Could not start dashboard automatically: ${openError.message}`)); + } + console.log(chalk.gray(` Start manually with: pr-agent dashboard`)); + } } catch (error: any) { spinner.fail('Analysis failed'); - + // Handle specific error types with user-friendly messages if (error instanceof ConfigurationError) { console.error(chalk.red(`\n❌ Configuration Error: ${error.message}`)); @@ -445,7 +733,7 @@ export async function analyzePR(options: AnalyzeOptions = {}): Promise { .replace(/sk-[a-zA-Z0-9_-]+/g, 'sk-***') .replace(/ghp_[a-zA-Z0-9]+/g, 'ghp_***') .substring(0, 500); // Limit length - + console.error(chalk.red(`\n❌ Error: ${sanitizedMessage}`)); if (options.verbose && error.stack) { console.error(chalk.gray('\nStack trace:')); @@ -459,7 +747,7 @@ export async function analyzePR(options: AnalyzeOptions = {}): Promise { /** * Display agent analysis results */ -function displayAgentResults(result: any, mode: AnalysisMode, verbose: boolean): void { +function displayAgentResults(result: any, mode: AnalysisMode, verbose: boolean, showClassification: boolean = false): void { console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); console.log(chalk.green.bold('\n✨ Agent Analysis Complete!\n')); @@ -479,12 +767,18 @@ function displayAgentResults(result: any, mode: AnalysisMode, verbose: boolean): console.log('\n'); } + // Display project classification only if explicitly requested + if (showClassification && result.projectClassification) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(result.projectClassification); + } + // Combined quick actions section - only fixes with line numbers (for PR comments) // Filter: only critical/warning, must have line number, sort critical first const prCommentFixes = result.fixes - ?.filter((f: Fix) => - (f.severity === 'critical' || f.severity === 'warning') && - f.line !== undefined && + ?.filter((f: Fix) => + (f.severity === 'critical' || f.severity === 'warning') && + f.line !== undefined && f.line !== null ) .sort((a: Fix, b: Fix) => { @@ -493,24 +787,24 @@ function displayAgentResults(result: any, mode: AnalysisMode, verbose: boolean): if (a.severity !== 'critical' && b.severity === 'critical') return 1; return 0; }) || []; - + // Add recommendations (from AI) - only if we have critical issues - const recommendations = (criticalFixes.length > 0 && result.recommendations) - ? result.recommendations.slice(0, 3) + const recommendations = (criticalFixes.length > 0 && result.recommendations) + ? result.recommendations.slice(0, 3) : []; - + if (prCommentFixes.length > 0 || recommendations.length > 0) { console.log(chalk.cyan.bold(`💡 Quick Actions\n`)); let actionIndex = 1; - + // Show fixes with line numbers (sorted critical first) prCommentFixes.forEach((fix: Fix) => { const severityIcon = fix.severity === 'critical' ? chalk.red('🔴') : chalk.yellow('🟡'); const severityLabel = fix.severity === 'critical' ? chalk.red.bold('CRITICAL') : chalk.yellow.bold('WARNING'); const sourceLabel = fix.source === 'semgrep' ? chalk.blue(' [Semgrep]') : chalk.magenta(' [AI]'); const shortComment = fix.comment.split('\n')[0].substring(0, 120); - + console.log(chalk.white(` ${actionIndex}. ${severityIcon} ${chalk.cyan(`\`${fix.file}:${fix.line}\``)} - ${severityLabel}${sourceLabel}`)); console.log(chalk.gray(` ${shortComment}${fix.comment.length > 120 ? '...' : ''}`)); console.log(''); @@ -524,7 +818,7 @@ function displayAgentResults(result: any, mode: AnalysisMode, verbose: boolean): let severityIcon = chalk.yellow('🟡'); let severityLabel = chalk.yellow.bold('WARNING'); let recText = rec; - + // Check if recommendation starts with **CRITICAL: or **WARNING: if (rec.match(/^\*\*CRITICAL:/i)) { severityIcon = chalk.red('🔴'); @@ -538,10 +832,10 @@ function displayAgentResults(result: any, mode: AnalysisMode, verbose: boolean): severityIcon = chalk.red('🔴'); severityLabel = chalk.red.bold('CRITICAL'); } - + const sourceLabel = chalk.magenta(' [AI]'); const shortComment = recText.substring(0, 120); - + // Format exactly like Semgrep: Number. Icon - LABEL [Source] console.log(chalk.white(` ${actionIndex}. ${severityIcon} - ${severityLabel}${sourceLabel}`)); // Indented comment line with severity prefix @@ -551,13 +845,65 @@ function displayAgentResults(result: any, mode: AnalysisMode, verbose: boolean): }); } - const totalFilteredFixes = result.fixes?.filter((f: Fix) => + const totalFilteredFixes = result.fixes?.filter((f: Fix) => (f.severity === 'critical' || f.severity === 'warning') && f.line !== undefined && f.line !== null ).length || 0; - + if (totalFilteredFixes > prCommentFixes.length) { console.log(chalk.gray(` ... and ${totalFilteredFixes - prCommentFixes.length} more issues\n`)); } + } + + // Show recommendations if available + if (result.recommendations.length > 0) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.cyan.bold('\n💡 Recommendations\n')); + result.recommendations.forEach((rec: string, i: number) => { + console.log(chalk.white(` ${i + 1}. ${rec}`)); + }); + console.log('\n'); + } + + // Show agent reasoning if available (minimal) + if (verbose && result.reasoning.length > 0 && result.reasoning.length <= 5) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.cyan.bold('\n🤔 Analysis Strategy\n')); + result.reasoning.forEach((reason: string, i: number) => { + if (reason.includes('Strategy:') || i === 0) { + console.log(chalk.gray(` ${reason.substring(0, 150)}${reason.length > 150 ? '...' : ''}`)); + } + }); + console.log('\n'); + } + + // Show arch-docs impact if used + if (result.archDocsImpact?.used) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.blue.bold('\n📚 Architecture Documentation Impact\n')); + + console.log(chalk.white(`Documents analyzed: ${result.archDocsImpact.docsAvailable}`)); + console.log(chalk.white(`Relevant sections used: ${result.archDocsImpact.sectionsUsed}\n`)); + + if (result.archDocsImpact.influencedStages.length > 0) { + console.log(chalk.cyan('Stages influenced by arch-docs:')); + result.archDocsImpact.influencedStages.forEach((stage: string) => { + const stageEmoji = stage === 'file-analysis' ? '🔍' : + stage === 'risk-detection' ? '⚠️' : + stage === 'complexity-calculation' ? '📊' : + stage === 'summary-generation' ? '📝' : + stage === 'refinement' ? '🔄' : '✨'; + console.log(chalk.white(` ${stageEmoji} ${stage}`)); + }); + console.log(''); + } + + if (result.archDocsImpact.keyInsights.length > 0) { + console.log(chalk.cyan('Key insights from arch-docs integration:\n')); + result.archDocsImpact.keyInsights.forEach((insight: string, i: number) => { + console.log(chalk.white(` ${i + 1}. ${insight}`)); + }); + console.log(''); + } } else { console.log(chalk.green.bold('✅ Status\n')); console.log(chalk.white(' No critical issues found.\n\n')); @@ -568,7 +914,260 @@ function displayAgentResults(result: any, mode: AnalysisMode, verbose: boolean): console.log(chalk.gray(`Total tokens used: ${result.totalTokensUsed.toLocaleString()}`)); } + // Show test suggestions if available + if (result.testSuggestions && result.testSuggestions.length > 0) { + const newTests = result.testSuggestions.filter((s: any) => !s.isEnhancement); + const enhancements = result.testSuggestions.filter((s: any) => s.isEnhancement); + + // Show new test suggestions + if (newTests.length > 0) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.yellow.bold(`\n🧪 Test Suggestions (${newTests.length} files need tests)\n`)); + + for (const suggestion of newTests) { + console.log(chalk.cyan(` 📝 ${suggestion.forFile}`)); + console.log(chalk.gray(` Framework: ${suggestion.testFramework}`)); + if (suggestion.testFilePath) { + console.log(chalk.gray(` Suggested test file: ${suggestion.testFilePath}`)); + } + console.log(chalk.white(` ${suggestion.description}\n`)); + + if (suggestion.testCode) { + console.log(chalk.gray(' ┌─────────────────────────────────────────')); + const codeLines = suggestion.testCode.split('\n').slice(0, 10); + codeLines.forEach((line: string) => { + console.log(chalk.gray(' │ ') + chalk.white(line)); + }); + if (suggestion.testCode.split('\n').length > 10) { + console.log(chalk.gray(' │ ... (copy full code below)')); + } + console.log(chalk.gray(' └─────────────────────────────────────────\n')); + } + } + } + + // Show test enhancement suggestions + if (enhancements.length > 0) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.green.bold(`\n🔬 Test Enhancement Suggestions (${enhancements.length} test files can be improved)\n`)); + + for (const suggestion of enhancements) { + console.log(chalk.cyan(` 📊 ${suggestion.existingTestFile || suggestion.testFilePath}`)); + console.log(chalk.gray(` Source: ${suggestion.forFile}`)); + console.log(chalk.white(` ${suggestion.description}\n`)); + + if (suggestion.testCode && suggestion.testCode.trim()) { + console.log(chalk.gray(' ┌─────────────────────────────────────────')); + const codeLines = suggestion.testCode.split('\n').slice(0, 15); + codeLines.forEach((line: string) => { + console.log(chalk.gray(' │ ') + chalk.white(line)); + }); + if (suggestion.testCode.split('\n').length > 15) { + console.log(chalk.gray(' │ ... (more enhancements available)')); + } + console.log(chalk.gray(' └─────────────────────────────────────────\n')); + } + } + } + } + + // Show coverage report if available + if (result.coverageReport && result.coverageReport.available) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.green.bold('\n📊 Test Coverage Report\n')); + + const coverage = result.coverageReport; + if (coverage.overallPercentage !== undefined) { + const emoji = coverage.overallPercentage >= 80 ? '🟢' : coverage.overallPercentage >= 60 ? '🟡' : '🔴'; + console.log(chalk.white(` ${emoji} Overall Coverage: ${coverage.overallPercentage.toFixed(1)}%`)); + } + + if (coverage.lineCoverage !== undefined) { + console.log(chalk.gray(` Lines: ${coverage.lineCoverage.toFixed(1)}%`)); + } + + if (coverage.branchCoverage !== undefined) { + console.log(chalk.gray(` Branches: ${coverage.branchCoverage.toFixed(1)}%`)); + } + + if (coverage.delta !== undefined) { + const deltaEmoji = coverage.delta >= 0 ? '📈' : '📉'; + const deltaColor = coverage.delta >= 0 ? chalk.green : chalk.red; + console.log(deltaColor(` ${deltaEmoji} Coverage Delta: ${coverage.delta >= 0 ? '+' : ''}${coverage.delta.toFixed(1)}%`)); + } + + if (coverage.coverageTool) { + console.log(chalk.gray(`\n Tool: ${coverage.coverageTool}`)); + } + console.log(''); + } + + // Show DevOps cost estimates if available + if (result.devOpsCostEstimates && result.devOpsCostEstimates.length > 0) { + console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.yellow.bold('\n💰 AWS Infrastructure Cost Estimates\n')); + + let totalCost = 0; + for (const estimate of result.devOpsCostEstimates) { + const emoji = estimate.confidence === 'high' ? '🟢' : estimate.confidence === 'medium' ? '🟡' : '🔴'; + console.log(chalk.white(` ${emoji} ${estimate.resourceType.toUpperCase()}: ~$${estimate.estimatedNewCost.toFixed(2)}/month`)); + if (estimate.details) { + console.log(chalk.gray(` ${estimate.details}`)); + } + totalCost += estimate.estimatedNewCost; + } + + console.log(chalk.cyan.bold(`\n 📊 Total Estimated Impact: ~$${totalCost.toFixed(2)}/month`)); + console.log(chalk.gray('\n ⚠️ Estimates are approximate. Actual costs depend on usage and configuration.\n')); + } + console.log(chalk.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')); } +/** + * Run Peer Review analysis against linked Jira tickets + * + * This extends the PR analysis with business context validation: + * - Fetches linked Jira tickets from PR title/branch + * - Rates ticket quality + * - Validates implementation against derived requirements + * - Provides senior-dev style verdict + */ +async function runPeerReview( + config: any, + diff: string, + title: string | undefined, + prAnalysisResult: any, + verbose: boolean, + providerOptions: { provider: SupportedProvider; apiKey: string; model?: string } +): Promise { + const spinner = ora('Running Peer Review analysis...').start(); + + try { + // Create LLM using the same provider as main analysis + const llm = ProviderFactory.createChatModel({ + provider: providerOptions.provider, + apiKey: providerOptions.apiKey, + model: providerOptions.model, + temperature: 0.2, + maxTokens: 50000, + }); + + // Create peer review integration from config, passing the LLM in EXECUTE mode + const peerReviewConfig = config.peerReview || {}; + const integration = createPeerReviewIntegration(peerReviewConfig, PeerReviewMode.EXECUTE, llm); + + if (!integration.isEnabled()) { + spinner.warn('Peer Review enabled but not configured. Add Jira settings to config.'); + console.log(chalk.gray(' Run: pr-agent config --set peerReview.instanceUrl=https://your.atlassian.net')); + console.log(chalk.gray(' Or configure MCP: peerReview.useMcp=true')); + if (verbose) { + console.log(chalk.gray(` Debug: peerReviewConfig=${JSON.stringify(peerReviewConfig)}`)); + } + return null; + } + + // Get branch name for ticket extraction + let branchName: string | undefined; + try { + branchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim(); + } catch { + // Ignore - branch name is optional + } + + // Get commit messages for ticket extraction + let commitMessages: string[] = []; + try { + const commits = execSync('git log --oneline -10', { encoding: 'utf-8' }); + commitMessages = commits.trim().split('\n'); + } catch { + // Ignore + } + + // Parse diff to get file info + const files = parseDiffFiles(diff); + + spinner.text = 'Extracting ticket references...'; + + // Run peer review analysis + const result = await integration.analyze({ + prTitle: title || 'Untitled PR', + prDescription: undefined, // Could extract from git commit body + branchName, + commitMessages, + diff, + files, + prSummary: prAnalysisResult.summary, + prRisks: prAnalysisResult.overallRisks, + prComplexity: prAnalysisResult.overallComplexity, + }); + + spinner.succeed('Peer Review analysis complete'); + + // Display peer review results + const output = formatPeerReviewOutput(result); + if (output) { + console.log(output); + } + + if (verbose && result.ticketReferences.length > 0) { + console.log(chalk.gray('Ticket references found:')); + result.ticketReferences.forEach((ref) => { + console.log(chalk.gray(` - ${ref.key} (from ${ref.source}, confidence: ${ref.confidence}%)`)); + }); + } + + return result; + } catch (error: any) { + spinner.fail('Peer Review analysis failed'); + console.error(chalk.yellow(`⚠️ ${error.message || 'Unknown error'}`)); + console.log(chalk.gray(' The main PR analysis completed successfully.')); + console.log(chalk.gray(' Peer Review is an optional enhancement - check Jira configuration.')); + return null; + } +} + +/** + * Parse diff to extract file information + */ +function parseDiffFiles(diff: string): Array<{ + path: string; + additions: number; + deletions: number; + status: string; +}> { + const files: Array<{ + path: string; + additions: number; + deletions: number; + status: string; + }> = []; + + const filePattern = /^diff --git a\/(.+?) b\/(.+?)$/gm; + let match; + + while ((match = filePattern.exec(diff)) !== null) { + const filePath = match[2] !== '/dev/null' ? match[2] : match[1]; + const isNew = match[1] === '/dev/null' || match[1].startsWith('dev/null'); + const isDeleted = match[2] === '/dev/null'; + // Count additions and deletions (simplified) + const fileStart = match.index; + const nextFileMatch = filePattern.exec(diff); + const fileEnd = nextFileMatch ? nextFileMatch.index : diff.length; + filePattern.lastIndex = match.index + 1; // Reset to continue from after current match + + const fileContent = diff.substring(fileStart, fileEnd); + const additions = (fileContent.match(/^\+[^+]/gm) || []).length; + const deletions = (fileContent.match(/^-[^-]/gm) || []).length; + + files.push({ + path: filePath, + additions, + deletions, + status: isNew ? 'added' : isDeleted ? 'deleted' : 'modified', + }); + } + + return files; +} diff --git a/src/cli/commands/config.command.ts b/src/cli/commands/config.command.ts index ab26517..131cd74 100644 --- a/src/cli/commands/config.command.ts +++ b/src/cli/commands/config.command.ts @@ -20,12 +20,13 @@ const DEFAULT_CONFIG = { anthropic: '', openai: '', google: '', + zhipu: '', }, ai: { - provider: 'claude', + provider: 'anthropic', model: 'claude-sonnet-4-5-20250929', temperature: 0.2, - maxTokens: 2000, + maxTokens: 50000, }, analysis: { defaultMode: 'full', @@ -54,6 +55,16 @@ const DEFAULT_CONFIG = { showStrategy: true, showRecommendations: true, }, + peerReview: { + enabled: true, + useMcp: false, + analyzeAcceptanceCriteria: true, + rateTicketQuality: true, + generateTestSuggestions: true, + checkScopeCreep: true, + includeTicketDetails: true, + verbose: false, + }, }; /** diff --git a/src/cli/commands/dashboard.command.ts b/src/cli/commands/dashboard.command.ts new file mode 100644 index 0000000..3fa05a7 --- /dev/null +++ b/src/cli/commands/dashboard.command.ts @@ -0,0 +1,64 @@ +import { Command } from 'commander'; +import express from 'express'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import open from 'open'; +import chalk from 'chalk'; +import { getDashboardStats, getRecentAnalyses } from '../../db/index.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export function registerDashboardCommand(program: Command) { + program + .command('dashboard') + .description('Open the local analysis dashboard') + .option('-p, --port ', 'Port to run the dashboard on', '3000') + .action(async (options) => { + const port = parseInt(options.port, 10); + const app = express(); + + // Serve static files from the public directory + // We need to resolve from dist/cli/commands/ to src/public or dist/public + // Assuming the build copies public to dist/public + const publicDir = path.resolve(__dirname, '../../public'); + + // Fallback for development (running from src) + const srcPublicDir = path.resolve(__dirname, '../../../src/public'); + + if (process.env.NODE_ENV === 'development') { + app.use(express.static(srcPublicDir)); + } else { + // In production (dist), public might not be copied by tsc, so check + app.use(express.static(srcPublicDir)); + } + + // API Routes + app.get('/dashboard/api/stats', (req, res) => { + try { + const stats = getDashboardStats(); + const recent = getRecentAnalyses(); + res.json({ stats, recent }); + } catch (error) { + console.error('Error fetching stats:', error); + res.status(500).json({ error: 'Failed to fetch stats' }); + } + }); + + // Serve index.html for all other routes (must be last) + app.get('/', (req, res) => { + res.sendFile(path.join(srcPublicDir, 'index.html')); + }); + + app.listen(port, async () => { + const url = `http://localhost:${port}`; + console.log(chalk.green(`Dashboard running at ${url}`)); + + try { + await open(url); + } catch (err) { + console.log(chalk.yellow(`Could not open browser automatically. Please visit ${url}`)); + } + }); + }); +} diff --git a/src/cli/commands/help.command.ts b/src/cli/commands/help.command.ts index 437f0e3..1fb68ed 100644 --- a/src/cli/commands/help.command.ts +++ b/src/cli/commands/help.command.ts @@ -52,7 +52,7 @@ export function displayHelp(): void { console.log(' Use --branch to override for a single analysis\n'); console.log(chalk.dim(' Advanced Options:')); - console.log(' --provider AI provider: anthropic|openai|google'); + console.log(' --provider AI provider: anthropic|openai|google|zhipu'); console.log(' --model Specific model to use'); console.log(' --title PR title (auto-detected from git)'); console.log(' --max-cost Maximum cost limit (default: $5.00)'); diff --git a/src/cli/index.ts b/src/cli/index.ts index 4c4c3d6..25fe5fa 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -6,6 +6,7 @@ import { Command } from 'commander'; import { analyzePR } from './commands/analyze.command.js'; import { registerConfigCommand } from './commands/config.command.js'; import { registerHelpCommand } from './commands/help.command.js'; +import { registerDashboardCommand } from './commands/dashboard.command.js'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -35,7 +36,7 @@ program .option('--staged', 'Analyze staged changes (git diff --staged)') .option('--branch ', 'Analyze against specific branch') .option('--title ', 'PR title (auto-detected from git)') - .option('--provider ', 'AI provider (anthropic|openai|google)') + .option('--provider ', 'AI provider (anthropic|openai|google|zhipu)') .option('--model ', 'Specific model to use') .option('--agent', 'Force intelligent agent (recommended for large diffs)') .option('--summary', 'Show summary only') @@ -44,12 +45,20 @@ program .option('--full', 'Show all modes (default)', true) .option('--arch-docs', 'Use architecture documentation from .arch-docs folder (auto-detected by default)') .option('--max-cost ', 'Maximum cost in dollars', '5.0') + .option('--show-classification', 'Show project type classification (business logic vs QA)', false) + .option('--scan-coverage', 'Run test coverage analysis using nyc/istanbul', false) + .option('--show-coverage', 'Display coverage metrics if available', false) + .option('--show-static-analysis', 'Run and display ESLint static analysis results', false) + .option('--peer-review', 'Enable Jira peer review integration', false) .option('--verbose', 'Enable verbose output', false) .action(analyzePR); // Config command registerConfigCommand(program); +// Dashboard command +registerDashboardCommand(program); + // Help command registerHelpCommand(program); diff --git a/src/cli/utils/config-loader.ts b/src/cli/utils/config-loader.ts index f6331e4..390410b 100644 --- a/src/cli/utils/config-loader.ts +++ b/src/cli/utils/config-loader.ts @@ -11,6 +11,7 @@ export interface UserConfig { anthropic?: string; openai?: string; google?: string; + zhipu?: string; }; ai?: { provider?: string; @@ -37,6 +38,37 @@ export interface UserConfig { showStrategy?: boolean; showRecommendations?: boolean; }; + /** + * Peer Review configuration - integrates with issue trackers (Jira, etc.) + * to validate PRs against tickets and acceptance criteria + */ + peerReview?: { + // Enable/disable peer review feature + enabled?: boolean; + // Issue tracker provider: 'jira' | 'linear' | 'azure-devops' | 'github-issues' + provider?: string; + // Use MCP server for Jira access (recommended) + useMcp?: boolean; + // Direct API access settings (fallback if MCP not available) + instanceUrl?: string; + email?: string; + apiToken?: string; + // Default project key + defaultProject?: string; + // Custom field IDs (Jira-specific) + acceptanceCriteriaField?: string; + storyPointsField?: string; + // Custom ticket patterns (regex) - defaults to PROJ-123 format + ticketPatterns?: string[]; + // Analysis options + analyzeAcceptanceCriteria?: boolean; + rateTicketQuality?: boolean; + generateTestSuggestions?: boolean; + checkScopeCreep?: boolean; + // Output options + includeTicketDetails?: boolean; + verbose?: boolean; + }; } /** @@ -190,6 +222,7 @@ export function getApiKey(provider: string, config?: UserConfig): string | undef anthropic: 'ANTHROPIC_API_KEY', openai: 'OPENAI_API_KEY', google: 'GOOGLE_API_KEY', + zhipu: 'ZHIPU_API_KEY', }; const envVar = envVarMap[provider.toLowerCase()]; diff --git a/src/db/index.ts b/src/db/index.ts new file mode 100644 index 0000000..30d928c --- /dev/null +++ b/src/db/index.ts @@ -0,0 +1,601 @@ +import Database from 'better-sqlite3'; +import path from 'path'; +import fs from 'fs'; +import { fileURLToPath } from 'url'; + +// Get the directory where this module is located, then navigate to project root +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Resolve DB path relative to the project root (from src/db or dist/db) +// This ensures the database is always in the same location regardless of cwd +function resolveDbPath(): string { + // Try environment variable first + if (process.env.PR_AGENT_DB_PATH) { + return process.env.PR_AGENT_DB_PATH; + } + + // Navigate up from src/db or dist/db to project root + const projectRoot = path.resolve(__dirname, '..', '..'); + return path.join(projectRoot, 'pr-agent.db'); +} + +const DB_PATH = resolveDbPath(); + +export interface AnalysisRecord { + id?: number; + pr_number: number; + repo_owner: string; + repo_name: string; + author: string; + title: string; + complexity: number; + risks_count: number; + risks: string; // JSON + recommendations: string; // JSON + timestamp: string; + // Dashboard improvements (PR #13) + created_tests_count?: number; + estimated_cost?: number; // Legacy field from PR #13 + // Smart change detection & DevOps analysis (v0.2.0) + devops_cost_monthly?: number; // Estimated monthly AWS infrastructure cost + devops_resources?: string; // JSON array of detected resources + has_test_suggestions?: number; // 1 if test suggestions were generated + test_suggestions_count?: number; + coverage_percentage?: number; + // Project classification cache (v0.3.0) + project_classification?: string; // JSON - cached classification result + // Peer Review / Jira Integration (v0.3.0) + peer_review_enabled?: number; // 1 if peer review was run + ticket_key?: string; // Primary Jira ticket key (e.g., PROJ-123) + ticket_quality_score?: number; // Overall ticket quality score (0-100) + ticket_quality_tier?: string; // excellent/good/adequate/poor/insufficient + ac_compliance_percentage?: number; // Acceptance criteria compliance (0-100) + ac_requirements_met?: number; // Number of requirements met + ac_requirements_total?: number; // Total number of requirements + peer_review_verdict?: string; // approve/request_changes/needs_discussion + peer_review_blockers?: string; // JSON array of blockers + peer_review_warnings?: string; // JSON array of warnings + implementation_completeness?: number; // 0-100 + quality_score?: number; // 0-100 +} + +let db: Database.Database; + +export function getDB(): Database.Database { + if (!db) { + db = new Database(DB_PATH); + initDB(); + } + return db; +} + +function initDB() { + const db = getDB(); + db.exec(` + CREATE TABLE IF NOT EXISTS pr_analysis ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + pr_number INTEGER, + repo_owner TEXT, + repo_name TEXT, + author TEXT, + title TEXT, + complexity INTEGER, + risks_count INTEGER, + risks TEXT, + recommendations TEXT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + created_tests_count INTEGER, + estimated_cost REAL, + devops_cost_monthly REAL, + devops_resources TEXT, + has_test_suggestions INTEGER, + test_suggestions_count INTEGER, + coverage_percentage REAL, + project_classification TEXT, + peer_review_enabled INTEGER, + ticket_key TEXT, + ticket_quality_score REAL, + ticket_quality_tier TEXT, + ac_compliance_percentage REAL, + ac_requirements_met INTEGER, + ac_requirements_total INTEGER, + peer_review_verdict TEXT, + peer_review_blockers TEXT, + peer_review_warnings TEXT, + implementation_completeness REAL, + quality_score REAL + ) + `); + + // Migration: Add columns to existing tables if they don't exist + try { + const tableInfo = db.prepare('PRAGMA table_info(pr_analysis)').all() as { name: string }[]; + const columnNames = tableInfo.map(col => col.name); + + // Dashboard improvements (PR #13) + if (!columnNames.includes('created_tests_count')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN created_tests_count INTEGER DEFAULT 0'); + } + if (!columnNames.includes('estimated_cost')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN estimated_cost REAL DEFAULT 0'); + } + + // DevOps/Infrastructure cost tracking (v0.2.0) + if (!columnNames.includes('devops_cost_monthly')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN devops_cost_monthly REAL'); + } + if (!columnNames.includes('devops_resources')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN devops_resources TEXT'); + } + if (!columnNames.includes('has_test_suggestions')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN has_test_suggestions INTEGER'); + } + if (!columnNames.includes('test_suggestions_count')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN test_suggestions_count INTEGER'); + } + if (!columnNames.includes('coverage_percentage')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN coverage_percentage REAL'); + } + // Project classification cache (v0.3.0) + if (!columnNames.includes('project_classification')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN project_classification TEXT'); + } + + // Peer Review / Jira Integration (v0.3.0) + if (!columnNames.includes('peer_review_enabled')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN peer_review_enabled INTEGER'); + } + if (!columnNames.includes('ticket_key')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ticket_key TEXT'); + } + if (!columnNames.includes('ticket_quality_score')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ticket_quality_score REAL'); + } + if (!columnNames.includes('ticket_quality_tier')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ticket_quality_tier TEXT'); + } + if (!columnNames.includes('ac_compliance_percentage')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ac_compliance_percentage REAL'); + } + if (!columnNames.includes('ac_requirements_met')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ac_requirements_met INTEGER'); + } + if (!columnNames.includes('ac_requirements_total')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN ac_requirements_total INTEGER'); + } + if (!columnNames.includes('peer_review_verdict')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN peer_review_verdict TEXT'); + } + if (!columnNames.includes('peer_review_blockers')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN peer_review_blockers TEXT'); + } + if (!columnNames.includes('peer_review_warnings')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN peer_review_warnings TEXT'); + } + if (!columnNames.includes('implementation_completeness')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN implementation_completeness REAL'); + } + if (!columnNames.includes('quality_score')) { + db.exec('ALTER TABLE pr_analysis ADD COLUMN quality_score REAL'); + } + } catch (e) { + // Ignore migration errors - columns may already exist + } +} + +export function saveAnalysis(record: Omit & { timestamp?: string }) { + const db = getDB(); + + // Prepare values with defaults for all optional fields + const safeRecord = { + ...record, + created_tests_count: record.created_tests_count || 0, + estimated_cost: record.estimated_cost || 0, + coverage_percentage: record.coverage_percentage || null, + // DevOps fields (v0.2.0) + devops_cost_monthly: record.devops_cost_monthly || null, + devops_resources: record.devops_resources || null, + has_test_suggestions: record.has_test_suggestions || null, + test_suggestions_count: record.test_suggestions_count || null, + // Peer review fields (v0.3.0) + peer_review_enabled: record.peer_review_enabled || null, + ticket_key: record.ticket_key || null, + ticket_quality_score: record.ticket_quality_score || null, + ticket_quality_tier: record.ticket_quality_tier || null, + ac_compliance_percentage: record.ac_compliance_percentage || null, + ac_requirements_met: record.ac_requirements_met || null, + ac_requirements_total: record.ac_requirements_total || null, + peer_review_verdict: record.peer_review_verdict || null, + peer_review_blockers: record.peer_review_blockers || null, + peer_review_warnings: record.peer_review_warnings || null, + implementation_completeness: record.implementation_completeness || null, + quality_score: record.quality_score || null, + }; + + if (record.timestamp) { + const stmt = db.prepare(` + INSERT INTO pr_analysis ( + pr_number, repo_owner, repo_name, author, title, + complexity, risks_count, risks, recommendations, timestamp, + created_tests_count, estimated_cost, + devops_cost_monthly, devops_resources, has_test_suggestions, test_suggestions_count, coverage_percentage, + project_classification, + peer_review_enabled, ticket_key, ticket_quality_score, ticket_quality_tier, + ac_compliance_percentage, ac_requirements_met, ac_requirements_total, + peer_review_verdict, peer_review_blockers, peer_review_warnings, + implementation_completeness, quality_score + ) VALUES ( + @pr_number, @repo_owner, @repo_name, @author, @title, + @complexity, @risks_count, @risks, @recommendations, @timestamp, + @created_tests_count, @estimated_cost, + @devops_cost_monthly, @devops_resources, @has_test_suggestions, @test_suggestions_count, @coverage_percentage, + @project_classification, + @peer_review_enabled, @ticket_key, @ticket_quality_score, @ticket_quality_tier, + @ac_compliance_percentage, @ac_requirements_met, @ac_requirements_total, + @peer_review_verdict, @peer_review_blockers, @peer_review_warnings, + @implementation_completeness, @quality_score + ) + `); + stmt.run(safeRecord); + } else { + const stmt = db.prepare(` + INSERT INTO pr_analysis ( + pr_number, repo_owner, repo_name, author, title, + complexity, risks_count, risks, recommendations, + created_tests_count, estimated_cost, + devops_cost_monthly, devops_resources, has_test_suggestions, test_suggestions_count, coverage_percentage, + project_classification, + peer_review_enabled, ticket_key, ticket_quality_score, ticket_quality_tier, + ac_compliance_percentage, ac_requirements_met, ac_requirements_total, + peer_review_verdict, peer_review_blockers, peer_review_warnings, + implementation_completeness, quality_score + ) VALUES ( + @pr_number, @repo_owner, @repo_name, @author, @title, + @complexity, @risks_count, @risks, @recommendations, + @created_tests_count, @estimated_cost, + @devops_cost_monthly, @devops_resources, @has_test_suggestions, @test_suggestions_count, @coverage_percentage, + @project_classification, + @peer_review_enabled, @ticket_key, @ticket_quality_score, @ticket_quality_tier, + @ac_compliance_percentage, @ac_requirements_met, @ac_requirements_total, + @peer_review_verdict, @peer_review_blockers, @peer_review_warnings, + @implementation_completeness, @quality_score + ) + `); + stmt.run(safeRecord); + } +} + +/** + * Get cached project classification for a repository + * Returns the most recent classification if available + */ +export function getProjectClassification(repoOwner: string, repoName: string): string | null { + const db = getDB(); + const result = db.prepare(` + SELECT project_classification + FROM pr_analysis + WHERE repo_owner = ? AND repo_name = ? AND project_classification IS NOT NULL + ORDER BY timestamp DESC + LIMIT 1 + `).get(repoOwner, repoName) as { project_classification: string } | undefined; + + return result?.project_classification || null; +} + +export function getCommonRecommendations(limit = 5) { + const db = getDB(); + const rows = db.prepare('SELECT recommendations FROM pr_analysis').all() as { recommendations: string }[]; + + const frequency: Record = {}; + + rows.forEach(row => { + try { + const recs = JSON.parse(row.recommendations) as string[]; + recs.forEach(rec => { + // Simple normalization: first 50 chars to group similar start phrases + // In reality, this needs NLP clustering, but simple grouping works for identical strings + const key = rec.trim(); + frequency[key] = (frequency[key] || 0) + 1; + }); + } catch (e) { + // ignore parse errors + } + }); + + return Object.entries(frequency) + .sort((a, b) => b[1] - a[1]) // Descending order + .slice(0, limit) + .map(([text, count]) => ({ text, count })); +} + +export function getComplexityDistribution() { + const db = getDB(); + // Group by complexity buckets + const rows = db.prepare(` + SELECT + CASE + WHEN complexity <= 2 THEN 'Low' + WHEN complexity <= 4 THEN 'Medium' + ELSE 'High' + END as category, + COUNT(*) as count + FROM pr_analysis + GROUP BY category + `).all() as { category: string, count: number }[]; + + const distribution = { Low: 0, Medium: 0, High: 0 }; + rows.forEach(r => { + if (r.category === 'Low') distribution.Low = r.count; + else if (r.category === 'Medium') distribution.Medium = r.count; + else if (r.category === 'High') distribution.High = r.count; + }); + + return Object.values(distribution); // [Low, Medium, High] +} + +export function getWeeklyQualityTrend() { + const db = getDB(); + // SQLite doesn't have great date functions, so we'll group by YYYY-MM-DD and aggregate in JS or simple substr + // Grouping by day for better granularity, frontend can aggregate to weeks if needed + const rows = db.prepare(` + SELECT + substr(timestamp, 1, 10) as date, + AVG(complexity) as avg_complexity, + COUNT(*) as count + FROM pr_analysis + GROUP BY date + ORDER BY date ASC + LIMIT 30 + `).all() as { date: string, avg_complexity: number, count: number }[]; + + return rows; +} + +export function getDashboardStats() { + const db = getDB(); + + // Total PRs + const totalPRs = db.prepare('SELECT COUNT(*) as count FROM pr_analysis').get() as { count: number }; + + // "Successful" PRs (defined as complexity < 3 and 0 risks for this MVP) + const successfulPRs = db.prepare('SELECT COUNT(*) as count FROM pr_analysis WHERE complexity < 3 AND risks_count = 0').get() as { count: number }; + + // Average Complexity + const avgComplexity = db.prepare('SELECT AVG(complexity) as avg FROM pr_analysis').get() as { avg: number }; + + // Stats per Creator + const perCreator = db.prepare(` + SELECT author, COUNT(*) as count, AVG(complexity) as avg_complexity + FROM pr_analysis + GROUP BY author + ORDER BY count DESC + LIMIT 10 + `).all(); + + const commonRecommendations = getCommonRecommendations(5); + const complexityDistribution = getComplexityDistribution(); + const qualityTrend = getWeeklyQualityTrend(); + + // New Aggregations + const totalTestsCreated = db.prepare('SELECT SUM(created_tests_count) as count FROM pr_analysis').get() as { count: number }; + const avgCoverage = db.prepare('SELECT AVG(coverage_percentage) as avg FROM pr_analysis WHERE coverage_percentage IS NOT NULL').get() as { avg: number }; + const terraformCost = db.prepare('SELECT SUM(estimated_cost) as cost FROM pr_analysis').get() as { cost: number }; + + // Jira Compliance Stats (v0.3.0) + const jiraComplianceStats = getJiraComplianceStats(); + + return { + totalPRs: totalPRs.count, + successRate: totalPRs.count > 0 ? (successfulPRs.count / totalPRs.count) * 100 : 0, + avgComplexity: avgComplexity.avg || 0, + perCreator, + commonRecommendations, + complexityDistribution, + qualityTrend, + // Dashboard improvements (PR #13) + metrics: { + testsCreated: totalTestsCreated.count || 0, + avgCoverage: avgCoverage.avg || 0, + terraformCost: terraformCost.cost || 0 + }, + // DevOps/Infrastructure cost data (v0.2.0) + devOpsCosts: getDevOpsCostStats(), + // Jira Compliance (v0.3.0) + jiraCompliance: jiraComplianceStats, + }; +} + +export function getRecentAnalyses(limit = 10) { + const db = getDB(); + return db.prepare('SELECT * FROM pr_analysis ORDER BY timestamp DESC LIMIT ?').all(limit); +} + +// ========== DevOps Cost Tracking Functions (v0.2.0) ========== + +export interface DevOpsCostStats { + totalMonthlyEstimate: number; + analysesWithDevOps: number; + averageDevOpsCost: number; + resourceTypes: Record; // Count by resource type + costTrend: Array<{ date: string; cost: number }>; + testSuggestionStats: { + analysesWithSuggestions: number; + totalSuggestions: number; + }; + coverageStats: { + analysesWithCoverage: number; + averageCoverage: number; + }; +} + +/** + * Get DevOps/Infrastructure cost statistics + */ +export function getDevOpsCostStats(): DevOpsCostStats { + const db = getDB(); + + // Total DevOps cost estimates + const devOpsTotals = db.prepare(` + SELECT + COALESCE(SUM(devops_cost_monthly), 0) as total_monthly, + COUNT(CASE WHEN devops_cost_monthly > 0 THEN 1 END) as analyses_with_devops + FROM pr_analysis + WHERE devops_cost_monthly IS NOT NULL + `).get() as { total_monthly: number; analyses_with_devops: number }; + + // Resource type breakdown (from JSON column) + const resourceRows = db.prepare(` + SELECT devops_resources + FROM pr_analysis + WHERE devops_resources IS NOT NULL AND devops_resources != '' + `).all() as { devops_resources: string }[]; + + const resourceTypes: Record = {}; + for (const row of resourceRows) { + try { + const resources = JSON.parse(row.devops_resources) as Array<{ resourceType: string }>; + for (const resource of resources) { + resourceTypes[resource.resourceType] = (resourceTypes[resource.resourceType] || 0) + 1; + } + } catch (e) { + // Ignore parse errors + } + } + + // Cost trend (last 30 days) + const costTrend = db.prepare(` + SELECT + substr(timestamp, 1, 10) as date, + COALESCE(SUM(devops_cost_monthly), 0) as cost + FROM pr_analysis + WHERE devops_cost_monthly IS NOT NULL + AND timestamp >= datetime('now', '-30 days') + GROUP BY date + ORDER BY date ASC + `).all() as { date: string; cost: number }[]; + + // Test suggestion stats + const testStats = db.prepare(` + SELECT + COUNT(CASE WHEN has_test_suggestions = 1 THEN 1 END) as analyses_with_suggestions, + COALESCE(SUM(test_suggestions_count), 0) as total_suggestions + FROM pr_analysis + `).get() as { analyses_with_suggestions: number; total_suggestions: number }; + + // Coverage stats + const coverageStats = db.prepare(` + SELECT + COUNT(CASE WHEN coverage_percentage IS NOT NULL THEN 1 END) as analyses_with_coverage, + COALESCE(AVG(coverage_percentage), 0) as avg_coverage + FROM pr_analysis + WHERE coverage_percentage IS NOT NULL + `).get() as { analyses_with_coverage: number; avg_coverage: number }; + + return { + totalMonthlyEstimate: devOpsTotals.total_monthly, + analysesWithDevOps: devOpsTotals.analyses_with_devops, + averageDevOpsCost: devOpsTotals.analyses_with_devops > 0 + ? devOpsTotals.total_monthly / devOpsTotals.analyses_with_devops + : 0, + resourceTypes, + costTrend, + testSuggestionStats: { + analysesWithSuggestions: testStats.analyses_with_suggestions, + totalSuggestions: testStats.total_suggestions, + }, + coverageStats: { + analysesWithCoverage: coverageStats.analyses_with_coverage, + averageCoverage: coverageStats.avg_coverage, + }, + }; +} + +// ========== Jira Compliance Stats (v0.3.0) ========== + +export interface JiraComplianceStats { + satisfied: number; // PRs with AC compliance >= 70% + missed: number; // PRs with AC compliance < 70% + totalWithPeerReview: number; + averageTicketQuality: number; + averageACCompliance: number; + verdictBreakdown: { + approved: number; + requestChanges: number; + needsDiscussion: number; + }; + ticketQualityTiers: { + excellent: number; + good: number; + adequate: number; + poor: number; + insufficient: number; + }; +} + +/** + * Get Jira compliance statistics for the dashboard + */ +export function getJiraComplianceStats(): JiraComplianceStats { + const db = getDB(); + + // Count PRs with peer review enabled + const peerReviewCounts = db.prepare(` + SELECT + COUNT(CASE WHEN peer_review_enabled = 1 THEN 1 END) as total_with_peer_review, + COUNT(CASE WHEN peer_review_enabled = 1 AND ac_compliance_percentage >= 70 THEN 1 END) as satisfied, + COUNT(CASE WHEN peer_review_enabled = 1 AND ac_compliance_percentage < 70 THEN 1 END) as missed + FROM pr_analysis + `).get() as { total_with_peer_review: number; satisfied: number; missed: number }; + + // Average scores + const avgScores = db.prepare(` + SELECT + COALESCE(AVG(ticket_quality_score), 0) as avg_ticket_quality, + COALESCE(AVG(ac_compliance_percentage), 0) as avg_ac_compliance + FROM pr_analysis + WHERE peer_review_enabled = 1 + `).get() as { avg_ticket_quality: number; avg_ac_compliance: number }; + + // Verdict breakdown + const verdictCounts = db.prepare(` + SELECT + COUNT(CASE WHEN peer_review_verdict = 'approve' THEN 1 END) as approved, + COUNT(CASE WHEN peer_review_verdict = 'request_changes' THEN 1 END) as request_changes, + COUNT(CASE WHEN peer_review_verdict = 'needs_discussion' THEN 1 END) as needs_discussion + FROM pr_analysis + WHERE peer_review_enabled = 1 + `).get() as { approved: number; request_changes: number; needs_discussion: number }; + + // Ticket quality tier breakdown + const tierCounts = db.prepare(` + SELECT + COUNT(CASE WHEN ticket_quality_tier = 'excellent' THEN 1 END) as excellent, + COUNT(CASE WHEN ticket_quality_tier = 'good' THEN 1 END) as good, + COUNT(CASE WHEN ticket_quality_tier = 'adequate' THEN 1 END) as adequate, + COUNT(CASE WHEN ticket_quality_tier = 'poor' THEN 1 END) as poor, + COUNT(CASE WHEN ticket_quality_tier = 'insufficient' THEN 1 END) as insufficient + FROM pr_analysis + WHERE peer_review_enabled = 1 + `).get() as { excellent: number; good: number; adequate: number; poor: number; insufficient: number }; + + return { + satisfied: peerReviewCounts.satisfied, + missed: peerReviewCounts.missed, + totalWithPeerReview: peerReviewCounts.total_with_peer_review, + averageTicketQuality: avgScores.avg_ticket_quality, + averageACCompliance: avgScores.avg_ac_compliance, + verdictBreakdown: { + approved: verdictCounts.approved, + requestChanges: verdictCounts.request_changes, + needsDiscussion: verdictCounts.needs_discussion, + }, + ticketQualityTiers: { + excellent: tierCounts.excellent, + good: tierCounts.good, + adequate: tierCounts.adequate, + poor: tierCounts.poor, + insufficient: tierCounts.insufficient, + }, + }; +} diff --git a/src/index.ts b/src/index.ts index 80e6022..8b63335 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,13 @@ import { Probot } from 'probot'; +import express, { Request, Response, Router } from 'express'; +import path from 'path'; +import { fileURLToPath } from 'url'; import { PRAnalyzerAgent } from './agents/pr-analyzer-agent.js'; +import { saveAnalysis, getDashboardStats, getRecentAnalyses } from './db/index.js'; +import { ExecutionMode, type AgentResult } from './types/agent.types.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); const provider = (process.env.AI_PROVIDER || 'anthropic').toLowerCase() as 'anthropic' | 'openai' | 'google'; const apiKey = process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.GOOGLE_API_KEY; @@ -109,9 +117,53 @@ function formatAnalysisForGitHub(result: any): string { return output; } -export default (app: Probot) => { +export default (app: Probot, { getRouter }: { getRouter?: (path?: string) => Router } = {}) => { app.log.info('🤖 PR Agent (LangChain) started'); + // Dashboard Routes + if (getRouter) { + // Determine public path for static assets + const finalPublicPath = path.join(__dirname, 'public'); + + const router = getRouter('/dashboard'); + if (router) { + // Serve static files + router.use(express.static(finalPublicPath)); + + // API Endpoints + router.get('/api/stats', (req: Request, res: Response) => { + try { + const stats = getDashboardStats(); + const recent = getRecentAnalyses(); + res.json({ stats, recent }); + } catch (error) { + app.log.error('Error fetching stats:', error); + res.status(500).json({ error: 'Failed to fetch stats' }); + } + }); + + router.get('/', (req: Request, res: Response) => { + res.sendFile(path.join(finalPublicPath, 'index.html')); + }); + + app.log.info('NOTE: Dashboard available at /dashboard'); + } + + // Handle root path + const rootRouter = getRouter(); + if (rootRouter) { + // Serve static files at root + rootRouter.use(express.static(finalPublicPath)); + + // Serve index.html at root + rootRouter.get('/', (req: Request, res: Response) => { + res.sendFile(path.join(finalPublicPath, 'index.html')); + }); + + app.log.info('Dashboard configured at root /'); + } + } + app.on(['pull_request.opened', 'pull_request.synchronize'], async (context) => { const { pull_request: pr, repository } = context.payload; @@ -128,11 +180,45 @@ export default (app: Probot) => { // Use LangChain agent for intelligent analysis app.log.info(`Running LangChain agent analysis with ${provider}...`); const agent = new PRAnalyzerAgent({ + mode: ExecutionMode.EXECUTE, // Probot always executes with API key provider: provider as any, apiKey, model, }); - const result = await agent.analyze(diff, pr.title); + const analysisResult = await agent.analyze(diff, pr.title); + + // Type guard: Probot always uses EXECUTE mode + if (analysisResult.mode === 'prompt_only') { + throw new Error('Unexpected prompt-only result in Probot EXECUTE mode'); + } + const result = analysisResult as AgentResult; + + // Save to Database + try { + // Calculate overall complexity from file analyses + let overallComplexity = 1; + if (result.fileAnalyses && result.fileAnalyses.size > 0) { + const complexities = Array.from(result.fileAnalyses.values()).map((f: any) => f.complexity || 1); + overallComplexity = Math.round(complexities.reduce((a: number, b: number) => a + b, 0) / complexities.length); + } + + // Get risks from fixes with critical/warning severity + const risks = result.fixes?.filter((f: any) => f.severity === 'critical' || f.severity === 'warning').map((f: any) => f.comment) || []; + + saveAnalysis({ + pr_number: pr.number, + repo_owner: repository.owner.login, + repo_name: repository.name, + author: pr.user.login, + title: pr.title, + complexity: overallComplexity, + risks_count: risks.length, + risks: JSON.stringify(risks), + recommendations: JSON.stringify(result.recommendations || []) + }); + } catch (dbError) { + app.log.error('Failed to save analysis to DB:', dbError); + } // Format the analysis for GitHub comment const summary = formatAnalysisForGitHub(result); diff --git a/src/issue-tracker/index.ts b/src/issue-tracker/index.ts new file mode 100644 index 0000000..5cef58f --- /dev/null +++ b/src/issue-tracker/index.ts @@ -0,0 +1,37 @@ +/** + * Issue Tracker Module + * + * Provides integration with issue tracking systems (Jira, Linear, etc.) + * for context-aware PR reviews. + */ + +// Types +export * from '../types/issue-tracker.types.js'; +export { type AnalysisPrompt } from '../types/agent.types.js'; + +// Jira Client +export { JiraMcpClient, type JiraConfig } from './jira-mcp-client.js'; + +// Integration +export { + PeerReviewIntegration, + createPeerReviewIntegration, + formatPeerReviewOutput, + formatPeerReviewMarkdown, + type PeerReviewConfig, + type PeerReviewContext, + type PeerReviewResult, + type PeerReviewUserConfig, +} from './peer-review-integration.js'; + +// Sub-Agent +export { + JiraSubAgent, + PeerReviewMode, + type JiraSubAgentResult, + type JiraSubAgentContext, + type TicketQualityRating, + type AcceptanceCriteriaValidation, + type PeerReviewAnalysis, + type PromptOnlyResult, +} from '../agents/jira-sub-agent.js'; diff --git a/src/issue-tracker/jira-mcp-client.ts b/src/issue-tracker/jira-mcp-client.ts new file mode 100644 index 0000000..1c29081 --- /dev/null +++ b/src/issue-tracker/jira-mcp-client.ts @@ -0,0 +1,686 @@ +/** + * Jira MCP Client + * + * Implements IssueTrackerProvider interface using the Atlassian MCP server. + * This client fetches Jira tickets and extracts ticket references from PR metadata. + * + * The MCP server is expected to provide Jira access through its tools. + * For environments without MCP, falls back to direct Jira API (if configured). + */ + +import { + IssueTrackerProvider, + IssueTrackerType, + IssueTicket, + IssueType, + IssuePriority, + TicketReference, + TicketExtractionContext, + IssueComment, + LinkedIssue, + SubtaskInfo, +} from '../types/issue-tracker.types.js'; + +// Jira-specific configuration +export interface JiraConfig { + // MCP-based access (preferred) + useMcp: boolean; + + // Direct API access (fallback) + instanceUrl?: string; + email?: string; + apiToken?: string; + + // Project settings + defaultProject?: string; + + // Custom field mappings + acceptanceCriteriaField?: string; // Custom field ID for AC + storyPointsField?: string; // Custom field ID for story points + + // Ticket patterns for extraction + ticketPatterns?: string[]; +} + +// Default patterns to match Jira ticket keys +const DEFAULT_TICKET_PATTERNS = [ + /([A-Z][A-Z0-9]+-\d+)/g, // Standard Jira format: PROJ-123 +]; + +export class JiraMcpClient implements IssueTrackerProvider { + readonly name = 'Jira'; + readonly type: IssueTrackerType = 'jira'; + + private config: JiraConfig; + private ticketPatterns: RegExp[]; + + // MCP callback for making MCP tool calls + // This is injected at runtime when MCP is available + private mcpCallback?: ( + tool: string, + params: Record + ) => Promise; + + constructor(config: JiraConfig) { + this.config = config; + this.ticketPatterns = this.buildTicketPatterns(); + } + + /** + * Set the MCP callback function for making MCP tool calls + */ + setMcpCallback( + callback: ( + tool: string, + params: Record + ) => Promise + ): void { + this.mcpCallback = callback; + } + + /** + * Check if the client is properly configured + */ + isConfigured(): boolean { + if (this.config.useMcp) { + return !!this.mcpCallback; + } + // Direct API requires instance URL and credentials + return !!( + this.config.instanceUrl && + this.config.email && + this.config.apiToken + ); + } + + /** + * Test connection to Jira + */ + async testConnection(): Promise { + try { + // Try to fetch any ticket to verify connection + if (this.config.useMcp && this.mcpCallback) { + // Use MCP to test connection + const result = await this.mcpCallback('atlassian:search-company-knowledge', { + query: 'test connection', + limit: 1, + }); + return !!result; + } else if (this.config.instanceUrl) { + // Direct API test + const response = await this.fetchJiraApi('/rest/api/3/myself'); + return response.ok; + } + return false; + } catch { + return false; + } + } + + /** + * Extract ticket references from PR metadata + */ + extractTicketReferences(context: TicketExtractionContext): TicketReference[] { + const references: Map = new Map(); + + // Extract from title (highest confidence) + this.extractFromText(context.prTitle, 'title', 95, references); + + // Extract from branch name (high confidence) + if (context.branchName) { + this.extractFromText(context.branchName, 'branch', 90, references); + } + + // Extract from description (medium confidence) + if (context.prDescription) { + this.extractFromText(context.prDescription, 'description', 80, references); + } + + // Extract from commit messages (lower confidence due to potential noise) + if (context.commitMessages) { + for (const msg of context.commitMessages) { + this.extractFromText(msg, 'commit', 70, references); + } + } + + // Sort by confidence (highest first) + return Array.from(references.values()).sort( + (a, b) => b.confidence - a.confidence + ); + } + + /** + * Fetch a single ticket by key + */ + async getTicket(key: string): Promise { + try { + const rawTicket = await this.fetchJiraTicket(key); + if (!rawTicket) return null; + return this.normalizeTicket(rawTicket); + } catch (error) { + console.error(`Failed to fetch ticket ${key}:`, error); + return null; + } + } + + /** + * Fetch multiple tickets by keys + */ + async getTickets(keys: string[]): Promise { + const tickets: IssueTicket[] = []; + + // Fetch in parallel with concurrency limit + const batchSize = 5; + for (let i = 0; i < keys.length; i += batchSize) { + const batch = keys.slice(i, i + batchSize); + const results = await Promise.all( + batch.map((key) => this.getTicket(key)) + ); + tickets.push(...results.filter((t): t is IssueTicket => t !== null)); + } + + return tickets; + } + + /** + * Search for tickets matching a query + */ + async searchTickets(query: string, limit = 10): Promise { + try { + if (this.config.useMcp && this.mcpCallback) { + // Use MCP search + const result = await this.mcpCallback('atlassian:search-company-knowledge', { + query, + limit, + }); + // Parse and normalize results + if (Array.isArray(result)) { + return result.map((r) => this.normalizeTicket(r as JiraApiIssue)); + } + } else { + // Direct JQL search + const jql = `text ~ "${query}" ORDER BY updated DESC`; + const response = await this.fetchJiraApi( + `/rest/api/3/search?jql=${encodeURIComponent(jql)}&maxResults=${limit}` + ); + if (response.ok) { + const data = await response.json() as { issues?: JiraApiIssue[] }; + return (data.issues || []).map((issue: JiraApiIssue) => + this.normalizeTicket(issue) + ); + } + } + } catch (error) { + console.error('Failed to search tickets:', error); + } + return []; + } + + /** + * Get comments for a ticket + */ + async getComments(ticketKey: string): Promise { + try { + const response = await this.fetchJiraApi( + `/rest/api/3/issue/${ticketKey}/comment` + ); + if (response.ok) { + const data = await response.json() as { comments?: JiraApiComment[] }; + return (data.comments || []).map((c: JiraApiComment) => { + let bodyText = ''; + if (typeof c.body === 'string') { + bodyText = c.body; + } else if (c.body && typeof c.body === 'object' && 'content' in c.body) { + bodyText = c.body.content?.[0]?.content?.[0]?.text || ''; + } + return { + id: c.id, + author: c.author?.displayName || 'Unknown', + body: bodyText, + createdAt: c.created, + }; + }); + } + } catch (error) { + console.error(`Failed to get comments for ${ticketKey}:`, error); + } + return []; + } + + // ========== Private Helper Methods ========== + + private buildTicketPatterns(): RegExp[] { + if (this.config.ticketPatterns?.length) { + return this.config.ticketPatterns.map((p) => new RegExp(p, 'g')); + } + return DEFAULT_TICKET_PATTERNS; + } + + private extractFromText( + text: string, + source: TicketReference['source'], + baseConfidence: number, + references: Map + ): void { + for (const pattern of this.ticketPatterns) { + // Reset lastIndex for global patterns + pattern.lastIndex = 0; + let match; + while ((match = pattern.exec(text)) !== null) { + const key = match[1] || match[0]; + const upperKey = key.toUpperCase(); + + // Skip if we already have this reference with higher confidence + const existing = references.get(upperKey); + if (existing && existing.confidence >= baseConfidence) { + continue; + } + + references.set(upperKey, { + key: upperKey, + source, + rawMatch: match[0], + confidence: baseConfidence, + }); + } + } + } + + private async fetchJiraTicket(key: string): Promise { + // Try MCP first if configured + if (this.config.useMcp && this.mcpCallback) { + try { + const result = await this.mcpCallback('atlassian:get-issue', { + issueKey: key, + }); + return result as JiraApiIssue; + } catch (mcpError: any) { + console.error(`[Jira MCP] Failed to fetch ticket ${key} via MCP:`, mcpError.message); + + // Try MCP search as fallback + try { + const searchResult = await this.mcpCallback('atlassian:search-company-knowledge', { + query: `key:${key}`, + limit: 1, + }); + if (Array.isArray(searchResult) && searchResult.length > 0) { + return searchResult[0] as JiraApiIssue; + } + } catch (searchError: any) { + console.error(`[Jira MCP] Search fallback also failed:`, searchError.message); + } + + // Fallback to API if MCP completely failed and API is configured + if (this.config.instanceUrl && this.config.email && this.config.apiToken) { + console.warn(`[Jira] Falling back to direct API for ticket ${key}`); + try { + const response = await this.fetchJiraApi(`/rest/api/3/issue/${key}?expand=renderedFields`); + if (response.ok) { + return response.json() as Promise; + } + } catch (apiError: any) { + console.error(`[Jira API] Failed to fetch ticket ${key}:`, apiError.message); + } + } else { + console.error(`[Jira] No API credentials configured for fallback`); + } + return null; + } + } + + // Direct API fetch (when MCP not configured) + if (this.config.instanceUrl && this.config.email && this.config.apiToken) { + try { + const response = await this.fetchJiraApi(`/rest/api/3/issue/${key}?expand=renderedFields`); + if (response.ok) { + return response.json() as Promise; + } + } catch (error: any) { + console.error(`[Jira API] Failed to fetch ticket ${key}:`, error.message); + } + } + + return null; + } + + private async fetchJiraApi(path: string): Promise { + if (!this.config.instanceUrl || !this.config.email || !this.config.apiToken) { + throw new Error('Jira API credentials not configured'); + } + + const url = `${this.config.instanceUrl}${path}`; + const auth = Buffer.from(`${this.config.email}:${this.config.apiToken}`).toString('base64'); + + return fetch(url, { + headers: { + Authorization: `Basic ${auth}`, + Accept: 'application/json', + }, + }); + } + + private normalizeTicket(raw: JiraApiIssue): IssueTicket { + const fields = raw.fields || {}; + + // Extract acceptance criteria from description or custom field + const acceptanceCriteria = this.extractAcceptanceCriteria(fields); + + // Normalize issue type + const issueType = this.normalizeIssueType(fields.issuetype?.name); + + // Normalize priority + const priority = this.normalizePriority(fields.priority?.name); + + // Extract linked issues + const linkedIssues = this.extractLinkedIssues(fields); + + // Extract subtasks + const subtasks = this.extractSubtasks(fields); + + // Check for visual documentation + const attachments = fields.attachment || []; + const hasScreenshots = attachments.some((a: JiraApiAttachment) => + a.mimeType?.startsWith('image/') + ); + const hasDiagrams = attachments.some( + (a: JiraApiAttachment) => + a.filename?.includes('diagram') || + a.filename?.includes('flow') || + a.mimeType?.includes('svg') + ); + + // Extract epic key - handle custom field which may be string or undefined + const epicKey = fields.epic?.key || (fields.customfield_10014 as string | undefined); + + return { + id: raw.id, + key: raw.key, + url: `${this.config.instanceUrl || ''}/browse/${raw.key}`, + title: fields.summary || '', + description: this.extractDescription(fields), + type: issueType, + status: fields.status?.name || 'Unknown', + priority, + assignee: fields.assignee?.displayName, + reporter: fields.reporter?.displayName, + labels: fields.labels || [], + components: (fields.components || []).map((c: { name: string }) => c.name), + project: fields.project?.key, + storyPoints: this.extractStoryPoints(fields), + acceptanceCriteria: acceptanceCriteria.text, + acceptanceCriteriaList: acceptanceCriteria.list, + testScenarios: this.extractTestScenarios(fields), + linkedTestCases: [], // Would need Zephyr/Xray integration + hasScreenshots, + hasDiagrams, + attachmentCount: attachments.length, + parentKey: fields.parent?.key, + epicKey, + linkedIssues, + subtasks, + createdAt: fields.created || '', + updatedAt: fields.updated || '', + rawData: raw as unknown as Record, + }; + } + + private extractDescription(fields: JiraApiFields): string { + // Handle Atlassian Document Format (ADF) or plain text + if (typeof fields.description === 'string') { + return fields.description; + } + if (fields.description?.content) { + return this.adfToText(fields.description); + } + return ''; + } + + private adfToText(adf: JiraAdfDocument): string { + // Simple ADF to text conversion + const extractText = (node: JiraAdfNode): string => { + if (node.type === 'text') { + return node.text || ''; + } + if (node.content) { + return node.content.map(extractText).join(''); + } + return ''; + }; + + return (adf.content || []) + .map((node) => { + const text = extractText(node); + // Add newlines for block elements + if (['paragraph', 'heading', 'bulletList', 'orderedList', 'listItem'].includes(node.type)) { + return text + '\n'; + } + return text; + }) + .join('') + .trim(); + } + + private extractAcceptanceCriteria(fields: JiraApiFields): { + text: string; + list: string[]; + } { + // Try custom field first + if (this.config.acceptanceCriteriaField) { + const customField = fields[this.config.acceptanceCriteriaField]; + if (customField) { + let text: string; + if (typeof customField === 'string') { + text = customField; + } else if (typeof customField === 'object' && customField !== null && 'type' in customField && 'version' in customField) { + text = this.adfToText(customField as JiraAdfDocument); + } else { + text = ''; + } + return { text, list: this.parseAcceptanceCriteriaList(text) }; + } + } + + // Extract from description - look for common AC patterns + const description = this.extractDescription(fields); + const acPatterns = [ + /acceptance\s*criteria[:\s]*\n([\s\S]*?)(?=\n\n|\n#|$)/i, + /definition\s*of\s*done[:\s]*\n([\s\S]*?)(?=\n\n|\n#|$)/i, + /requirements[:\s]*\n([\s\S]*?)(?=\n\n|\n#|$)/i, + /given[\s\S]*?when[\s\S]*?then/gi, // Gherkin-style + ]; + + for (const pattern of acPatterns) { + const match = description.match(pattern); + if (match) { + const text = match[1] || match[0]; + return { text, list: this.parseAcceptanceCriteriaList(text) }; + } + } + + return { text: '', list: [] }; + } + + private parseAcceptanceCriteriaList(text: string): string[] { + const items: string[] = []; + + // Parse bullet points + const bulletMatches = text.match(/^[\s]*[-*•]\s*(.+)$/gm); + if (bulletMatches) { + items.push(...bulletMatches.map((m) => m.replace(/^[\s]*[-*•]\s*/, '').trim())); + } + + // Parse numbered items + const numberedMatches = text.match(/^[\s]*\d+[.)]\s*(.+)$/gm); + if (numberedMatches) { + items.push(...numberedMatches.map((m) => m.replace(/^[\s]*\d+[.)]\s*/, '').trim())); + } + + // Parse checkboxes + const checkboxMatches = text.match(/^[\s]*\[[ x]\]\s*(.+)$/gim); + if (checkboxMatches) { + items.push(...checkboxMatches.map((m) => m.replace(/^[\s]*\[[ x]\]\s*/i, '').trim())); + } + + // If no structured items found, split by newlines + if (items.length === 0 && text.trim()) { + const lines = text.split('\n').filter((l) => l.trim().length > 10); + items.push(...lines.map((l) => l.trim())); + } + + return [...new Set(items)]; // Remove duplicates + } + + private extractStoryPoints(fields: JiraApiFields): number | undefined { + // Try common story point field IDs + const spFields = [ + this.config.storyPointsField, + 'customfield_10016', // Common Jira Cloud + 'customfield_10004', // Another common one + 'storyPoints', + ].filter(Boolean); + + for (const field of spFields) { + if (field && fields[field] !== undefined) { + const value = fields[field]; + if (typeof value === 'number') return value; + if (typeof value === 'string') return parseFloat(value) || undefined; + } + } + return undefined; + } + + private extractTestScenarios(fields: JiraApiFields): string[] { + const description = this.extractDescription(fields); + const scenarios: string[] = []; + + // Look for test scenario patterns + const testPatterns = [ + /test\s*scenario[s]?[:\s]*\n([\s\S]*?)(?=\n\n|\n#|$)/i, + /test\s*cases?[:\s]*\n([\s\S]*?)(?=\n\n|\n#|$)/i, + /scenario[:\s]+(.+)/gi, + ]; + + for (const pattern of testPatterns) { + const matches = description.match(pattern); + if (matches) { + scenarios.push(...this.parseAcceptanceCriteriaList(matches[1] || matches[0])); + } + } + + return [...new Set(scenarios)]; + } + + private normalizeIssueType(typeName?: string): IssueType { + if (!typeName) return 'other'; + const lower = typeName.toLowerCase(); + if (lower.includes('bug')) return 'bug'; + if (lower.includes('feature')) return 'feature'; + if (lower.includes('story')) return 'story'; + if (lower.includes('epic')) return 'epic'; + if (lower.includes('subtask') || lower.includes('sub-task')) return 'subtask'; + if (lower.includes('task')) return 'task'; + if (lower.includes('improvement')) return 'improvement'; + if (lower.includes('spike')) return 'spike'; + return 'other'; + } + + private normalizePriority(priorityName?: string): IssuePriority { + if (!priorityName) return 'none'; + const lower = priorityName.toLowerCase(); + if (lower.includes('critical') || lower.includes('blocker') || lower.includes('highest')) { + return 'critical'; + } + if (lower.includes('high')) return 'high'; + if (lower.includes('medium') || lower.includes('normal')) return 'medium'; + if (lower.includes('low') || lower.includes('minor')) return 'low'; + return 'none'; + } + + private extractLinkedIssues(fields: JiraApiFields): LinkedIssue[] { + const links = fields.issuelinks || []; + return links.map((link: JiraApiIssueLink) => { + const linkedIssue = link.inwardIssue || link.outwardIssue; + const linkType = link.inwardIssue ? link.type?.inward : link.type?.outward; + return { + key: linkedIssue?.key || '', + type: linkType || 'relates to', + title: linkedIssue?.fields?.summary || '', + status: linkedIssue?.fields?.status?.name || '', + }; + }); + } + + private extractSubtasks(fields: JiraApiFields): SubtaskInfo[] { + const subtasks = fields.subtasks || []; + return subtasks.map((st: JiraApiSubtask) => ({ + key: st.key, + title: st.fields?.summary || '', + status: st.fields?.status?.name || '', + })); + } +} + +// ========== Jira API Types ========== + +interface JiraApiIssue { + id: string; + key: string; + fields: JiraApiFields; +} + +interface JiraApiFields { + summary?: string; + description?: string | JiraAdfDocument; + issuetype?: { name: string }; + status?: { name: string }; + priority?: { name: string }; + assignee?: { displayName: string }; + reporter?: { displayName: string }; + labels?: string[]; + components?: Array<{ name: string }>; + project?: { key: string }; + parent?: { key: string }; + epic?: { key: string }; + created?: string; + updated?: string; + attachment?: JiraApiAttachment[]; + issuelinks?: JiraApiIssueLink[]; + subtasks?: JiraApiSubtask[]; + [key: string]: unknown; // Custom fields +} + +interface JiraAdfDocument { + type: string; + version: number; + content?: JiraAdfNode[]; +} + +interface JiraAdfNode { + type: string; + text?: string; + content?: JiraAdfNode[]; +} + +interface JiraApiAttachment { + id: string; + filename: string; + mimeType: string; +} + +interface JiraApiIssueLink { + type?: { inward: string; outward: string }; + inwardIssue?: { key: string; fields?: { summary?: string; status?: { name: string } } }; + outwardIssue?: { key: string; fields?: { summary?: string; status?: { name: string } } }; +} + +interface JiraApiSubtask { + key: string; + fields?: { summary?: string; status?: { name: string } }; +} + +interface JiraApiComment { + id: string; + author?: { displayName: string }; + body?: string | JiraAdfDocument; + created: string; +} diff --git a/src/issue-tracker/peer-review-integration.ts b/src/issue-tracker/peer-review-integration.ts new file mode 100644 index 0000000..4fcc556 --- /dev/null +++ b/src/issue-tracker/peer-review-integration.ts @@ -0,0 +1,765 @@ +/** + * Peer Review Integration + * + * This module integrates the Jira sub-agent with the main PR analysis workflow. + * It handles: + * - Extracting ticket references from PR metadata + * - Fetching tickets from issue trackers + * - Running the Jira sub-agent analysis + * - Formatting the combined output + */ + +import { JiraMcpClient, JiraConfig } from './jira-mcp-client.js'; +import { + JiraSubAgent, + JiraSubAgentResult, + JiraSubAgentContext, + PeerReviewMode, + PromptOnlyResult, +} from '../agents/jira-sub-agent.js'; +import { + IssueTrackerProvider, + IssueTrackerConfig, + IssueTrackerType, + IssueTicket, + TicketReference, +} from '../types/issue-tracker.types.js'; +import { BaseLanguageModel } from '@langchain/core/language_models/base'; + +// ========== Types ========== + +export interface PeerReviewConfig { + issueTracker: IssueTrackerConfig; +} + +export interface PeerReviewContext { + prTitle: string; + prDescription?: string; + branchName?: string; + commitMessages?: string[]; + diff: string; + files: Array<{ + path: string; + additions: number; + deletions: number; + status: string; + }>; + // From existing PR analysis + prSummary?: string; + prRisks?: string[]; + prComplexity?: number; +} + +export interface PeerReviewResult { + enabled: boolean; + mode?: 'execute' | 'prompt_only'; + ticketReferences: TicketReference[]; + linkedTickets: IssueTicket[]; + primaryTicket?: IssueTicket; + analysis?: JiraSubAgentResult; + promptOnlyResult?: PromptOnlyResult; + error?: string; +} + +// ========== Main Integration Class ========== + +export class PeerReviewIntegration { + private provider: IssueTrackerProvider | null = null; + private subAgent: JiraSubAgent | null = null; + private config: IssueTrackerConfig; + private mode: PeerReviewMode; + + constructor( + config: IssueTrackerConfig, + mode: PeerReviewMode = PeerReviewMode.EXECUTE, + llm?: BaseLanguageModel + ) { + this.config = config; + this.mode = mode; + this.initializeProvider(); + + // Create sub-agent with appropriate mode + if (mode === PeerReviewMode.EXECUTE && llm) { + this.subAgent = new JiraSubAgent(mode, llm); + } else if (mode === PeerReviewMode.PROMPT_ONLY) { + this.subAgent = new JiraSubAgent(mode); + } + } + + /** + * Set the LLM for the sub-agent (EXECUTE mode only) + */ + setLLM(llm: BaseLanguageModel): void { + if (this.mode === PeerReviewMode.EXECUTE) { + this.subAgent = new JiraSubAgent(this.mode, llm); + } + } + + /** + * Set MCP callback for the Jira client + */ + setMcpCallback( + callback: (tool: string, params: Record) => Promise + ): void { + if (this.provider && this.provider instanceof JiraMcpClient) { + (this.provider as JiraMcpClient).setMcpCallback(callback); + } + } + + /** + * Check if peer review is enabled and properly configured + */ + isEnabled(): boolean { + return this.config.enabled && this.provider !== null && this.provider.isConfigured(); + } + + /** + * Run peer review analysis + */ + async analyze(context: PeerReviewContext): Promise { + if (!this.config.enabled) { + return { + enabled: false, + ticketReferences: [], + linkedTickets: [], + }; + } + + if (!this.provider) { + return { + enabled: true, + ticketReferences: [], + linkedTickets: [], + error: 'Issue tracker provider not configured', + }; + } + + try { + // Step 1: Extract ticket references from PR metadata + const ticketReferences = this.provider.extractTicketReferences({ + prTitle: context.prTitle, + prDescription: context.prDescription, + branchName: context.branchName, + commitMessages: context.commitMessages, + }); + + if (ticketReferences.length === 0) { + return { + enabled: true, + ticketReferences: [], + linkedTickets: [], + error: 'No ticket references found in PR title, description, or branch name', + }; + } + + // Step 2: Fetch tickets + const ticketKeys = [...new Set(ticketReferences.map((r) => r.key))]; + const linkedTickets = await this.provider.getTickets(ticketKeys); + + if (linkedTickets.length === 0) { + return { + enabled: true, + ticketReferences, + linkedTickets: [], + error: `Could not fetch tickets: ${ticketKeys.join(', ')}`, + }; + } + + // Primary ticket is the one with highest confidence reference + const primaryTicket = linkedTickets[0]; + + // Step 3: Run sub-agent analysis (if configured) + let analysis: JiraSubAgentResult | undefined; + let promptOnlyResult: PromptOnlyResult | undefined; + + if (this.subAgent && primaryTicket) { + const subAgentContext: JiraSubAgentContext = { + ticket: primaryTicket, + prTitle: context.prTitle, + prDescription: context.prDescription, + diff: context.diff, + files: context.files, + prSummary: context.prSummary, + prRisks: context.prRisks, + }; + + const result = await this.subAgent.analyze(subAgentContext); + + // Handle both EXECUTE and PROMPT_ONLY modes + if ('mode' in result && result.mode === 'prompt_only') { + promptOnlyResult = result; + } else { + analysis = result as JiraSubAgentResult; + } + } + + return { + enabled: true, + mode: this.mode === PeerReviewMode.PROMPT_ONLY ? 'prompt_only' : 'execute', + ticketReferences, + linkedTickets, + primaryTicket, + analysis, + promptOnlyResult, + }; + } catch (error) { + return { + enabled: true, + ticketReferences: [], + linkedTickets: [], + error: `Peer review analysis failed: ${error instanceof Error ? error.message : String(error)}`, + }; + } + } + + // ========== Private Methods ========== + + private initializeProvider(): void { + if (!this.config.enabled) return; + + switch (this.config.provider) { + case 'jira': + this.provider = new JiraMcpClient(this.config.providerConfig as unknown as JiraConfig); + break; + + // Future providers + case 'linear': + case 'azure-devops': + case 'github-issues': + case 'gitlab-issues': + console.warn(`Provider ${this.config.provider} not yet implemented, using Jira fallback`); + break; + + default: + console.warn(`Unknown provider: ${this.config.provider}`); + } + } +} + +// ========== Factory Function ========== + +/** + * Create a PeerReviewIntegration from user config + * + * @param userConfig - User configuration from .pragent.config.json + * @param mode - Execution mode (EXECUTE for CLI with API key, PROMPT_ONLY for MCP without API key) + * @param llm - LangChain LLM instance (required for EXECUTE mode, ignored for PROMPT_ONLY mode) + */ +export function createPeerReviewIntegration( + userConfig: PeerReviewUserConfig, + mode: PeerReviewMode = PeerReviewMode.EXECUTE, + llm?: BaseLanguageModel +): PeerReviewIntegration { + const issueTrackerConfig: IssueTrackerConfig = { + enabled: userConfig.enabled ?? false, + provider: (userConfig.provider as IssueTrackerType) || 'jira', + providerConfig: { + useMcp: userConfig.useMcp ?? true, + instanceUrl: userConfig.instanceUrl, + email: userConfig.email, + apiToken: userConfig.apiToken, + defaultProject: userConfig.defaultProject, + acceptanceCriteriaField: userConfig.acceptanceCriteriaField, + storyPointsField: userConfig.storyPointsField, + ticketPatterns: userConfig.ticketPatterns, + }, + analyzeAcceptanceCriteria: userConfig.analyzeAcceptanceCriteria ?? true, + rateTicketQuality: userConfig.rateTicketQuality ?? true, + generateTestSuggestions: userConfig.generateTestSuggestions ?? true, + checkScopeCreep: userConfig.checkScopeCreep ?? true, + ticketPatterns: userConfig.ticketPatterns, + includeTicketDetails: userConfig.includeTicketDetails ?? true, + verbose: userConfig.verbose ?? false, + }; + + return new PeerReviewIntegration(issueTrackerConfig, mode, llm); +} + +// ========== User Config Type ========== + +/** + * User-facing configuration for peer review + * This is what goes in .pragent.config.json + */ +export interface PeerReviewUserConfig { + // Enable/disable peer review feature + enabled?: boolean; + + // Issue tracker provider + provider?: string; // 'jira' | 'linear' | 'azure-devops' | 'github-issues' + + // MCP-based access (preferred for Jira) + useMcp?: boolean; + + // Direct API access (fallback) + instanceUrl?: string; // e.g., "https://company.atlassian.net" + email?: string; + apiToken?: string; + + // Project settings + defaultProject?: string; + + // Custom field mappings (Jira-specific) + acceptanceCriteriaField?: string; + storyPointsField?: string; + + // Ticket patterns for extraction (regex) + ticketPatterns?: string[]; + + // Analysis settings + analyzeAcceptanceCriteria?: boolean; + rateTicketQuality?: boolean; + generateTestSuggestions?: boolean; + checkScopeCreep?: boolean; + + // Output settings + includeTicketDetails?: boolean; + verbose?: boolean; +} + +// ========== Output Formatting ========== + +/** + * Format peer review results for CLI output + */ +export function formatPeerReviewOutput(result: PeerReviewResult): string { + const lines: string[] = []; + + if (!result.enabled) { + return ''; // Silently skip if not enabled + } + + lines.push(''); + lines.push('═══════════════════════════════════════════════════════════════'); + lines.push(' 🔍 PEER REVIEW ANALYSIS'); + lines.push('═══════════════════════════════════════════════════════════════'); + lines.push(''); + + if (result.error) { + lines.push(`⚠️ ${result.error}`); + lines.push(''); + return lines.join('\n'); + } + + // Ticket Information + if (result.primaryTicket) { + const ticket = result.primaryTicket; + lines.push('📋 LINKED TICKET'); + lines.push('───────────────────────────────────────────────────────────────'); + lines.push(` Key: ${ticket.key}`); + lines.push(` Title: ${ticket.title}`); + lines.push(` Type: ${ticket.type.toUpperCase()}`); + lines.push(` Status: ${ticket.status}`); + if (ticket.storyPoints) { + lines.push(` Points: ${ticket.storyPoints}`); + } + lines.push(''); + } + + // Ticket Quality Rating + if (result.analysis?.ticketQuality) { + const quality = result.analysis.ticketQuality; + const scoreEmoji = getScoreEmoji(quality.overallScore); + + lines.push('📊 TICKET QUALITY RATING'); + lines.push('───────────────────────────────────────────────────────────────'); + lines.push(` Overall Score: ${scoreEmoji} ${quality.overallScore}/100 (${quality.tier.toUpperCase()})`); + lines.push(''); + lines.push(' Dimension Scores:'); + lines.push(` • Description Clarity: ${formatScore(quality.dimensions.descriptionClarity)}`); + lines.push(` • Acceptance Criteria: ${formatScore(quality.dimensions.acceptanceCriteriaQuality)}`); + lines.push(` • Testability: ${formatScore(quality.dimensions.testabilityScore)}`); + lines.push(` • Scope Definition: ${formatScore(quality.dimensions.scopeDefinition)}`); + lines.push(` • Technical Context: ${formatScore(quality.dimensions.technicalContext)}`); + lines.push(` • Visual Documentation: ${formatScore(quality.dimensions.visualDocumentation)}`); + lines.push(` • Completeness: ${formatScore(quality.dimensions.completeness)}`); + lines.push(''); + + if (!quality.reviewable) { + lines.push(` ⚠️ Ticket Not Reviewable: ${quality.reviewabilityReason}`); + lines.push(''); + } + + if (quality.feedback.weaknesses.length > 0) { + lines.push(' ⚠️ Ticket Weaknesses:'); + quality.feedback.weaknesses.forEach((w) => lines.push(` • ${w}`)); + lines.push(''); + } + } + + // Requirements Validation (derived from ticket analysis) + if (result.analysis?.acValidation) { + const validation = result.analysis.acValidation; + const complianceEmoji = getScoreEmoji(validation.compliancePercentage); + + lines.push('✅ REQUIREMENTS VALIDATION'); + lines.push('───────────────────────────────────────────────────────────────'); + lines.push(` Compliance: ${complianceEmoji} ${validation.compliancePercentage}%`); + lines.push(''); + + // Show derived requirements (what the agent understood from the ticket) + if (validation.derivedRequirements && validation.derivedRequirements.length > 0) { + lines.push(' 📋 DERIVED REQUIREMENTS (from ticket analysis):'); + validation.derivedRequirements.forEach((req) => { + const importanceIcon = { + essential: '🔴', + expected: '🟡', + nice_to_have: '🟢', + }[req.importance]; + const sourceLabel = { + description: 'desc', + explicit_ac: 'AC', + implied: 'implied', + ticket_type: 'type', + technical_context: 'tech', + }[req.source]; + lines.push(` ${importanceIcon} [${sourceLabel}] ${req.requirement}`); + }); + lines.push(''); + } + + // Show each requirement's validation status + lines.push(' 📊 REQUIREMENT STATUS:'); + validation.criteriaAnalysis.forEach((c) => { + const statusEmoji = { + met: '✅', + partial: '🟡', + unmet: '❌', + unclear: '❓', + }[c.status]; + lines.push(` ${statusEmoji} ${c.criteriaText.substring(0, 60)}${c.criteriaText.length > 60 ? '...' : ''}`); + if (c.status !== 'met') { + lines.push(` └─ ${c.explanation.substring(0, 70)}${c.explanation.length > 70 ? '...' : ''}`); + } + }); + lines.push(''); + + // Show gaps with impact + if (validation.gaps.length > 0) { + lines.push(' ❌ COVERAGE GAPS:'); + validation.gaps.forEach((gap) => { + const severityEmoji = { critical: '🔴', major: '🟠', minor: '🟡' }[gap.severity]; + lines.push(` ${severityEmoji} [${gap.severity.toUpperCase()}] ${gap.gapDescription}`); + lines.push(` └─ Impact: ${gap.impact}`); + }); + lines.push(''); + } + + // Show missing behaviors identified by the agent + if (validation.missingBehaviors && validation.missingBehaviors.length > 0) { + lines.push(' ⚠️ MISSING BEHAVIORS:'); + validation.missingBehaviors.forEach((b) => lines.push(` • ${b}`)); + lines.push(''); + } + } + + // Overall Peer Review Assessment + if (result.analysis?.peerReview) { + const review = result.analysis.peerReview; + + // Final verdict banner + const verdictEmoji = { + approve: '✅', + request_changes: '❌', + needs_discussion: '💬', + }[review.verdict.recommendation]; + const verdictText = { + approve: 'APPROVED', + request_changes: 'CHANGES REQUESTED', + needs_discussion: 'NEEDS DISCUSSION', + }[review.verdict.recommendation]; + + lines.push('🎯 PEER REVIEW VERDICT'); + lines.push('───────────────────────────────────────────────────────────────'); + lines.push(` ${verdictEmoji} ${verdictText} (Confidence: ${review.verdict.confidenceLevel}%)`); + lines.push(''); + lines.push(` ${review.verdict.summary}`); + lines.push(''); + + lines.push(' Scores:'); + lines.push(` • Implementation Completeness: ${formatScore(review.implementationCompleteness)}`); + lines.push(` • Quality Score: ${formatScore(review.qualityScore)}`); + lines.push(''); + + // Blockers with details + if (review.blockers.length > 0) { + lines.push(' 🚫 BLOCKERS (must fix before merge):'); + review.blockers.forEach((b) => { + lines.push(` • ${b.issue}`); + lines.push(` Reason: ${b.reason}`); + if (b.location) { + lines.push(` Location: ${b.location}`); + } + }); + lines.push(''); + } + + // Warnings with details + if (review.warnings.length > 0) { + lines.push(' ⚠️ WARNINGS (should address):'); + review.warnings.forEach((w) => { + lines.push(` • ${w.issue}`); + if (w.reason) { + lines.push(` Reason: ${w.reason}`); + } + }); + lines.push(''); + } + + // Regression risks - critical for senior dev perspective + if (review.regressionRisks && review.regressionRisks.length > 0) { + lines.push(' ⚡ POTENTIAL REGRESSION RISKS:'); + review.regressionRisks.forEach((r) => { + const likelihoodEmoji = { high: '🔴', medium: '🟠', low: '🟡' }[r.likelihood]; + lines.push(` ${likelihoodEmoji} ${r.risk}`); + lines.push(` Affected: ${r.affectedArea}`); + lines.push(` Why: ${r.reasoning}`); + }); + lines.push(''); + } + + // Uncovered scenarios - what the senior dev noticed isn't handled + if (review.uncoveredScenarios && review.uncoveredScenarios.length > 0) { + lines.push(' 🔍 SCENARIOS NOT HANDLED:'); + review.uncoveredScenarios.forEach((s) => { + const impactEmoji = { critical: '🔴', major: '🟠', minor: '🟡' }[s.impact]; + lines.push(` ${impactEmoji} ${s.scenario}`); + if (s.relatedCriteria) { + lines.push(` Related to: ${s.relatedCriteria}`); + } + }); + lines.push(''); + } + + // Scope analysis + if (review.scopeAnalysis.scopeCreepRisk) { + lines.push(' ⚠️ SCOPE CREEP DETECTED:'); + lines.push(` ${review.scopeAnalysis.scopeCreepDetails || 'Changes may exceed ticket scope'}`); + if (review.scopeAnalysis.outOfScope.length > 0) { + lines.push(' Out of scope changes:'); + review.scopeAnalysis.outOfScope.slice(0, 3).forEach((s) => lines.push(` • ${s}`)); + } + lines.push(''); + } + + // Recommendations + if (review.recommendations.length > 0) { + lines.push(' 💡 RECOMMENDATIONS:'); + review.recommendations.slice(0, 3).forEach((r) => lines.push(` • ${r}`)); + lines.push(''); + } + } + + lines.push('═══════════════════════════════════════════════════════════════'); + lines.push(''); + + return lines.join('\n'); +} + +function getScoreEmoji(score: number): string { + if (score >= 85) return '🟢'; + if (score >= 70) return '🟡'; + if (score >= 50) return '🟠'; + return '🔴'; +} + +function formatScore(score: number): string { + const emoji = getScoreEmoji(score); + const bar = '█'.repeat(Math.floor(score / 10)) + '░'.repeat(10 - Math.floor(score / 10)); + return `${emoji} ${bar} ${score}`; +} + +/** + * Format peer review results for GitHub PR comment + */ +export function formatPeerReviewMarkdown(result: PeerReviewResult): string { + if (!result.enabled || result.error) { + return ''; + } + + const lines: string[] = []; + + lines.push('## 🔍 Peer Review Analysis'); + lines.push(''); + + // Verdict banner at the top + if (result.analysis?.peerReview) { + const review = result.analysis.peerReview; + const verdictEmoji = { + approve: '✅', + request_changes: '❌', + needs_discussion: '💬', + }[review.verdict.recommendation]; + const verdictText = { + approve: 'APPROVED', + request_changes: 'CHANGES REQUESTED', + needs_discussion: 'NEEDS DISCUSSION', + }[review.verdict.recommendation]; + + lines.push(`### ${verdictEmoji} Verdict: ${verdictText}`); + lines.push(''); + lines.push(`> ${review.verdict.summary}`); + lines.push(''); + } + + // Ticket Information + if (result.primaryTicket) { + const ticket = result.primaryTicket; + lines.push(`### 📋 Linked Ticket: [${ticket.key}](${ticket.url})`); + lines.push(''); + lines.push(`**${ticket.title}**`); + lines.push(''); + lines.push(`| Property | Value |`); + lines.push(`|----------|-------|`); + lines.push(`| Type | ${ticket.type} |`); + lines.push(`| Status | ${ticket.status} |`); + if (ticket.storyPoints) { + lines.push(`| Story Points | ${ticket.storyPoints} |`); + } + lines.push(''); + } + + // Ticket Quality + if (result.analysis?.ticketQuality) { + const quality = result.analysis.ticketQuality; + lines.push('### 📊 Ticket Quality'); + lines.push(''); + lines.push(`**Overall Score: ${quality.overallScore}/100** (${quality.tier})`); + lines.push(''); + + if (!quality.reviewable) { + lines.push(`> ⚠️ **Warning:** ${quality.reviewabilityReason}`); + lines.push(''); + } + + if (quality.feedback.weaknesses.length > 0) { + lines.push('
'); + lines.push('Ticket Weaknesses'); + lines.push(''); + quality.feedback.weaknesses.forEach((w) => lines.push(`- ${w}`)); + lines.push(''); + lines.push('
'); + lines.push(''); + } + } + + // Requirements Validation (derived from ticket) + if (result.analysis?.acValidation) { + const validation = result.analysis.acValidation; + lines.push('### ✅ Requirements Validation'); + lines.push(''); + lines.push(`**Compliance: ${validation.compliancePercentage}%**`); + lines.push(''); + + // Show derived requirements + if (validation.derivedRequirements && validation.derivedRequirements.length > 0) { + lines.push('
'); + lines.push('📋 Derived Requirements (from ticket analysis)'); + lines.push(''); + lines.push('| Importance | Source | Requirement |'); + lines.push('|------------|--------|-------------|'); + validation.derivedRequirements.forEach((req) => { + const importanceEmoji = { essential: '🔴', expected: '🟡', nice_to_have: '🟢' }[req.importance]; + lines.push(`| ${importanceEmoji} ${req.importance} | ${req.source} | ${req.requirement} |`); + }); + lines.push(''); + lines.push('
'); + lines.push(''); + } + + lines.push('| Status | Requirement |'); + lines.push('|--------|-------------|'); + validation.criteriaAnalysis.forEach((c) => { + const statusEmoji = { met: '✅', partial: '🟡', unmet: '❌', unclear: '❓' }[c.status]; + lines.push(`| ${statusEmoji} ${c.status} | ${c.criteriaText.substring(0, 80)}${c.criteriaText.length > 80 ? '...' : ''} |`); + }); + lines.push(''); + + if (validation.gaps.length > 0) { + lines.push('#### ❌ Coverage Gaps'); + lines.push(''); + validation.gaps.forEach((gap) => { + lines.push(`- **[${gap.severity}]** ${gap.gapDescription}`); + lines.push(` - _Impact:_ ${gap.impact}`); + }); + lines.push(''); + } + } + + // Peer Review Details + if (result.analysis?.peerReview) { + const review = result.analysis.peerReview; + lines.push('### 🎯 Assessment Details'); + lines.push(''); + lines.push(`| Metric | Score |`); + lines.push(`|--------|-------|`); + lines.push(`| Implementation Completeness | ${review.implementationCompleteness}% |`); + lines.push(`| Quality Score | ${review.qualityScore}% |`); + lines.push(`| Confidence | ${review.verdict.confidenceLevel}% |`); + lines.push(''); + + if (review.blockers.length > 0) { + lines.push('#### 🚫 Blockers (Must Fix)'); + lines.push(''); + review.blockers.forEach((b) => { + lines.push(`- **${b.issue}**`); + lines.push(` - ${b.reason}`); + if (b.location) { + lines.push(` - 📍 ${b.location}`); + } + }); + lines.push(''); + } + + if (review.warnings.length > 0) { + lines.push('#### ⚠️ Warnings (Should Address)'); + lines.push(''); + review.warnings.forEach((w) => { + lines.push(`- **${w.issue}**`); + if (w.reason) { + lines.push(` - ${w.reason}`); + } + }); + lines.push(''); + } + + // Regression risks + if (review.regressionRisks && review.regressionRisks.length > 0) { + lines.push('
'); + lines.push('⚡ Potential Regression Risks'); + lines.push(''); + review.regressionRisks.forEach((r) => { + lines.push(`- **${r.risk}** (${r.likelihood} likelihood)`); + lines.push(` - Affects: ${r.affectedArea}`); + lines.push(` - Reason: ${r.reasoning}`); + }); + lines.push(''); + lines.push('
'); + lines.push(''); + } + + // Uncovered scenarios + if (review.uncoveredScenarios && review.uncoveredScenarios.length > 0) { + lines.push('
'); + lines.push('🔍 Scenarios Not Handled'); + lines.push(''); + review.uncoveredScenarios.forEach((s) => { + lines.push(`- **[${s.impact}]** ${s.scenario}`); + if (s.relatedCriteria) { + lines.push(` - Related to: ${s.relatedCriteria}`); + } + }); + lines.push(''); + lines.push('
'); + lines.push(''); + } + + // Scope creep + if (review.scopeAnalysis.scopeCreepRisk) { + lines.push('> ⚠️ **Scope Creep Detected:** ' + (review.scopeAnalysis.scopeCreepDetails || 'Changes may exceed ticket scope')); + lines.push(''); + } + } + + return lines.join('\n'); +} diff --git a/src/mcp/README.md b/src/mcp/README.md new file mode 100644 index 0000000..6ab785f --- /dev/null +++ b/src/mcp/README.md @@ -0,0 +1,233 @@ +# PR Agent MCP Server + +LLM-agnostic MCP (Model Context Protocol) server for AI-powered pull request analysis. + +## Overview + +The PR Agent MCP Server provides the same powerful analysis capabilities as the CLI, but designed for integration with any MCP-compatible tool (Claude Code, Cursor, Windsurf, etc.). The calling tool's LLM performs the AI analysis, making this server completely LLM-agnostic. + +## Installation + +### From npm (Recommended) + +```bash +npm install -g @techdebtgpt/pr-agent +``` + +### From Source + +```bash +git clone https://github.com/techdebtgpt/pr-agent.git +cd pr-agent +npm install --legacy-peer-deps +npm run build +``` + +## Configuration + +### Claude Code + +Add to `~/.claude/settings.json` or project `.claude/settings.json`: + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "pr-agent-mcp" + } + } +} +``` + +### Cursor / Windsurf / Other MCP Clients + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "npx", + "args": ["-y", "@techdebtgpt/pr-agent", "mcp"] + } + } +} +``` + +### From Source + +```json +{ + "mcpServers": { + "pr-agent": { + "command": "node", + "args": ["/path/to/pr-agent/dist/mcp/server.js"] + } + } +} +``` + +## Available Tools + +### `analyze` + +Analyzes PR/branch changes with comprehensive diff parsing, risk detection, and complexity scoring. + +**Parameters:** + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `branch` | string | auto-detected | Base branch to compare against | +| `staged` | boolean | false | Analyze staged changes instead | +| `title` | string | from git | PR title for ticket extraction | +| `cwd` | string | current dir | Working directory | +| `peerReview` | boolean | from config | Enable Jira ticket validation | +| `archDocs` | boolean | from config | Include architecture docs context | +| `verbose` | boolean | false | Include debug information | + +**Example Usage:** +``` +Analyze my current branch changes against main +``` + +**Output includes:** +- Summary (files changed, lines, languages) +- Complexity score (1-5) with factors +- Detected risks (security, quality, breaking changes) +- File change details +- Linked Jira tickets (if found) +- Architecture documentation context (if available) + +### `dashboard` + +Starts a local web dashboard for viewing analysis history and metrics. + +**Parameters:** + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `port` | number | 3000 | Port to run dashboard on | + +**Example Usage:** +``` +Start the PR Agent dashboard on port 3001 +``` + +## Configuration File + +The MCP server uses `.pragent.config.json` (same as CLI): + +```json +{ + "git": { + "defaultBranch": "origin/main" + }, + "analysis": { + "language": "typescript", + "framework": "react" + }, + "peerReview": { + "enabled": true, + "provider": "jira", + "defaultProject": "PROJ" + } +} +``` + +> Note: AI provider settings (`ai.provider`, `apiKeys`) are ignored by the MCP server since the calling tool provides the AI. + +## Risk Detection + +The server detects these risk patterns: + +**Security (Critical):** +- Hardcoded passwords, API keys, secrets +- Command injection vulnerabilities +- SQL injection patterns + +**Security (Warning):** +- `eval()` usage +- `innerHTML` / `dangerouslySetInnerHTML` + +**Quality:** +- TODO/FIXME comments +- Excessive console.log statements +- Missing error handling + +**Breaking Changes:** +- Removed/modified exports + +## Peer Review (Jira Integration) + +When Jira is configured, the server extracts ticket references from: +1. PR title (e.g., "PROJ-123: Add feature") +2. Branch name (e.g., "feature/PROJ-123-add-feature") +3. Commit messages + +The calling LLM can then use Jira MCP tools to validate against ticket requirements. + +## Architecture Documentation + +If your repo has a `.arch-docs` folder, the server: +1. Loads all markdown documentation +2. Identifies relevant sections based on changed files +3. Includes context in analysis output + +## Data Storage + +Analysis results are saved to `pr-agent.db` (SQLite) for dashboard viewing: +- PR analysis history +- Code quality trends +- ROI metrics + +## Publishing + +### To npm + +```bash +npm login +npm publish +``` + +### To MCP Registry + +See [Publishing Guide](https://modelcontextprotocol.info/tools/registry/publishing/) + +### To Smithery + +1. Connect your GitHub repository at [smithery.ai](https://smithery.ai) +2. Start a deployment +3. Your server becomes discoverable and installable + +## Security Considerations + +- The server runs locally in the user's environment +- No external API calls are made (LLM-agnostic) +- Credentials in config files stay local +- Use environment variables for sensitive data + +## Troubleshooting + +### Server Not Starting + +```bash +# Test manually +node dist/mcp/server.js + +# Check for errors +pr-agent-mcp 2>&1 +``` + +### Config Not Loading + +The server looks for `.pragent.config.json` in: +1. Current working directory +2. Parent directories (up to root) + +### Dashboard Port in Use + +``` +Start the dashboard on port 3001 +``` + +## License + +MIT License - see [LICENSE](../../LICENSE) diff --git a/src/mcp/constants.ts b/src/mcp/constants.ts new file mode 100644 index 0000000..58a8428 --- /dev/null +++ b/src/mcp/constants.ts @@ -0,0 +1,180 @@ +/** + * MCP Server Constants + * All magic strings, numbers, and configuration defaults + */ + +import { z } from 'zod'; + +// MCP Server Metadata +export const MCP_SERVER_NAME = 'pr-agent'; +export const MCP_SERVER_VERSION = '1.0.0'; + +// Dashboard Configuration +export const DEFAULT_DASHBOARD_PORT = 3000; +export const DASHBOARD_API_STATS_PATH = '/dashboard/api/stats'; +export const DASHBOARD_CATCH_ALL_PATH = '/{*splat}'; + +// Git Configuration +export const DEFAULT_GIT_LOG_LIMIT = 10; +export const DEFAULT_MAX_BUFFER = 200 * 1024 * 1024; // 200MB + +// Analysis Configuration +export const DEFAULT_PROMPT_LIMIT_VERBOSE = 30000; +export const DEFAULT_PROMPT_LIMIT_NORMAL = 15000; +export const EXPECTED_TOKEN_USAGE_MINIMUM = 5000; + +// Prompt Step Emojis +export const PROMPT_STEP_EMOJIS: Record = { + fileAnalysis: '📄', + riskDetection: '⚠️', + summaryGeneration: '📋', + selfRefinement: '✨', + ticketQuality: '🎯', + acValidation: '✅', + peerReview: '👥', +}; + +// Default Prompt Step Emoji +export const DEFAULT_PROMPT_EMOJI = '🔹'; + +// Error Messages +export const ERROR_MESSAGES = { + NO_CHANGES: (currentBranch: string, baseBranch: string) => + `No changes detected between ${currentBranch} and ${baseBranch || 'staged'}`, + ANALYSIS_FAILED: (message: string) => + `❌ Analysis failed: ${message}\n\nMake sure you are in a git repository with changes to analyze.`, + SAVE_FAILED: (message: string) => `❌ Failed to save analysis results: ${message}`, + DASHBOARD_ALREADY_RUNNING: (port: number) => + `✅ Dashboard is already running at http://localhost:${port}\n\nOpen this URL in your browser to view PR analysis history and statistics.`, + DASHBOARD_PORT_IN_USE: (port: number) => `Port ${port} is already in use`, + DASHBOARD_START_FAILED: (message: string) => `Failed to start dashboard: ${message}`, + PEER_REVIEW_FAILED: (message: string) => `Peer review was enabled but failed: ${message}`, +}; + +// Success Messages +export const SUCCESS_MESSAGES = { + ANALYSIS_SAVED: (port: number) => + `✅ Analysis results saved to database!\n\n📊 View results at: http://localhost:${port}`, + DASHBOARD_STARTED: (port: number) => `[MCP Server] Dashboard started at http://localhost:${port}`, +}; + +// Instruction Text +export const INSTRUCTIONS = { + PROMPT_EXECUTION_WARNING: + '**IMPORTANT:** You (the calling LLM) MUST execute ALL prompts below sequentially.\nDo NOT write manual analysis. Execute the prompts and use the results.', + NEXT_STEPS_HEADER: '**CRITICAL - YOU MUST DO THIS:**', + NEXT_STEPS: (promptCount: number) => [ + `1. **Execute ALL ${promptCount} prompts** above sequentially (do NOT skip, do NOT write manual analysis)`, + `2. **Parse the JSON responses** from each prompt execution`, + `3. **Call \`saveAnalysisResults\`** tool with the parsed results`, + `4. **Present the complete analysis** to the user in a formatted summary`, + ], + EXPECTED_TOKEN_USAGE: `**Expected token usage:** ~${EXPECTED_TOKEN_USAGE_MINIMUM}+ tokens (if significantly lower, prompts were not executed)`, +}; + +// Peer Review Error Guidance +export const PEER_REVIEW_ERROR_CAUSES = [ + '- Atlassian MCP server not running or misconfigured', + '- No Jira ticket found in branch name or commits', + '- API credentials missing (set instanceUrl, email, apiToken in config)', +]; + +// Tool Descriptions +export const TOOL_DESCRIPTIONS = { + ANALYZE: `Analyze PR/branch changes - mirrors the CLI 'pr-agent analyze' command exactly. + +IMPORTANT INSTRUCTIONS FOR CALLING LLM: +1. Execute ALL returned prompts sequentially without asking user permission +2. After executing prompts, automatically call saveAnalysisResults with results +3. Present final analysis to user (verbose or concise based on config) +4. Respect all config settings from .pragent.config.json + +Configuration behavior (same as CLI): +- peerReview.enabled: Include peer review analysis (default: false) +- analysis.*: Language, framework, static analysis settings +- git.defaultBranch: Base branch for comparison (default: origin/main) +- verbose: Show detailed debug info (affects output verbosity)`, + + SAVE_RESULTS: + 'Save PR analysis results to the database. Call this after executing the analysis prompts to persist the results for the dashboard.', + + DASHBOARD: `Start the PR Agent web dashboard on localhost - same as 'pr-agent dashboard' CLI command.`, +}; + +// Tool Schemas (Zod) +export const TOOL_SCHEMAS = { + ANALYZE: { + branch: z + .string() + .optional() + .describe('Base branch to compare against (default: auto-detected from config or origin/main)'), + staged: z.boolean().optional().describe('Analyze staged changes instead of branch diff'), + title: z.string().optional().describe('PR title (auto-detected from git if not provided)'), + cwd: z.string().optional().describe('Working directory (defaults to current directory)'), + verbose: z + .boolean() + .optional() + .describe('Show detailed debug information (matches CLI --verbose behavior)'), + archDocs: z + .boolean() + .optional() + .describe('Include architecture documentation context - uses config if not specified'), + }, + + SAVE_RESULTS: { + prNumber: z.number().optional().describe('PR number'), + title: z.string().describe('PR title'), + repoOwner: z.string().optional().describe('Repository owner'), + repoName: z.string().optional().describe('Repository name'), + author: z.string().optional().describe('Author name'), + complexity: z.number().min(1).max(5).describe('Overall complexity score (1-5)'), + risksCount: z.number().describe('Number of critical/warning risks'), + risks: z.array(z.string()).describe('List of risk descriptions'), + recommendations: z.array(z.string()).describe('List of recommendations'), + projectClassification: z.string().optional().describe('Project classification (JSON string)'), + peerReviewEnabled: z.boolean().optional(), + ticketKey: z.string().optional().describe('Jira ticket key (e.g., TODO-2)'), + ticketQualityScore: z.number().optional().describe('Ticket quality score (0-100)'), + ticketQualityTier: z.string().optional().describe('Ticket quality tier'), + acCompliancePercentage: z.number().optional().describe('AC compliance percentage'), + acRequirementsMet: z.number().optional(), + acRequirementsTotal: z.number().optional(), + peerReviewVerdict: z + .string() + .optional() + .describe('approve/request_changes/needs_discussion'), + peerReviewBlockers: z.array(z.string()).optional(), + peerReviewWarnings: z.array(z.string()).optional(), + implementationCompleteness: z.number().optional(), + qualityScore: z.number().optional(), + devopsCostMonthly: z.number().optional().describe('Estimated monthly infrastructure cost'), + devopsResources: z.string().optional().describe('JSON array of detected infrastructure resources'), + }, + + DASHBOARD: { + port: z.number().optional().describe('Port to run the dashboard on (default: 3000)'), + }, +}; + +// Git Patterns +export const GIT_PATTERNS = { + SSH_REMOTE: /git@[^:]+:([^/]+)\/(.+?)(?:\.git)?$/, + HTTPS_REMOTE: /https?:\/\/[^/]+\/([^/]+)\/(.+?)(?:\.git)?$/, + FILE_DIFF_HEADER: /^diff --git a\/(.*) b\/(.*)$/gm, +}; + +// File Status Icons +export const FILE_STATUS_ICONS: Record = { + A: '➕', + D: '➖', + M: '📝', +}; + +// Default Values +export const DEFAULTS = { + REPO_OWNER: 'local', + REPO_NAME: 'unknown', + BRANCH_NAME: 'unknown', + AUTHOR: 'unknown', + DEFAULT_BRANCH: 'origin/main', +}; diff --git a/src/mcp/index.ts b/src/mcp/index.ts new file mode 100644 index 0000000..761a93a --- /dev/null +++ b/src/mcp/index.ts @@ -0,0 +1,8 @@ +/** + * PR Agent MCP Server + * + * LLM-agnostic MCP server that exposes PR analysis utilities. + * This module re-exports the server for programmatic use. + */ + +export * from './server.js'; diff --git a/src/mcp/server.ts b/src/mcp/server.ts new file mode 100644 index 0000000..49b6655 --- /dev/null +++ b/src/mcp/server.ts @@ -0,0 +1,108 @@ +#!/usr/bin/env node + +/** + * PR Agent MCP Server + * + * Modular MCP server following SOLID principles and separation of concerns. + * This file serves as the entry point and tool registration layer only. + * All business logic is delegated to specialized service classes. + * + * Architecture: + * - server.ts (this file): Tool registration and MCP protocol handling + * - services/: Stateless service classes (git, diff parsing, formatting, etc.) + * - tools/: Tool handler classes (one per MCP tool) + * - constants.ts: Centralized configuration and messages + * - types.ts: MCP-specific type definitions + * + * The calling LLM (Claude Code, Cursor, etc.) provides AI-powered insights + * after receiving the analysis response. + * + * Note: When Claude Code adds MCP sampling support (Issue #1785), + * the StubChatModel can be replaced with MCPChatModel for true pass-through LLM access. + */ + +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { z } from 'zod'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +// __dirname workaround for ES modules +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +// Import service classes and tool handlers +import { DashboardService } from './services/index.js'; +import { AnalyzeTool, SaveResultsTool, DashboardTool } from './tools/index.js'; +import { + MCP_SERVER_NAME, + MCP_SERVER_VERSION, + TOOL_DESCRIPTIONS, + TOOL_SCHEMAS, +} from './constants.js'; + +// Create MCP server +const server = new McpServer({ + name: MCP_SERVER_NAME, + version: MCP_SERVER_VERSION, +}); + +// Initialize shared services +const dashboardService = new DashboardService(); + +// Initialize tool handlers with dependencies +const analyzeTool = new AnalyzeTool(dashboardService); +const saveResultsTool = new SaveResultsTool(); +const dashboardTool = new DashboardTool(dashboardService); + +/** + * analyze - Main PR analysis tool (mirrors CLI 'pr-agent analyze' command) + * + * Returns analysis prompts that the calling LLM MUST automatically execute. + * Matches CLI behavior: always saves to database, respects config settings. + */ +server.tool( + 'analyze', + TOOL_DESCRIPTIONS.ANALYZE, + TOOL_SCHEMAS.ANALYZE, + async (args) => { + return await analyzeTool.execute(args); + } +); + +/** + * saveAnalysisResults - Save analysis results to database after LLM execution + * Called by the LLM after executing the prompts returned by analyze tool + */ +server.tool( + 'saveAnalysisResults', + TOOL_DESCRIPTIONS.SAVE_RESULTS, + TOOL_SCHEMAS.SAVE_RESULTS, + async (args) => { + return await saveResultsTool.execute(args); + } +); + +/** + * dashboard - Start the web dashboard (same as CLI 'pr-agent dashboard') + */ +server.tool( + 'dashboard', + TOOL_DESCRIPTIONS.DASHBOARD, + TOOL_SCHEMAS.DASHBOARD, + async (args) => { + return await dashboardTool.execute(args, __dirname); + } +); + +// Main entry point +async function main() { + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error('PR Agent MCP Server started - LLM-agnostic mode with PROMPT_ONLY'); +} + +main().catch((error) => { + console.error('Fatal error:', error); + process.exit(1); +}); diff --git a/src/mcp/services/dashboard.service.ts b/src/mcp/services/dashboard.service.ts new file mode 100644 index 0000000..172a84b --- /dev/null +++ b/src/mcp/services/dashboard.service.ts @@ -0,0 +1,140 @@ +/** + * Dashboard Service + * Manages the HTTP dashboard server + * Single Responsibility: Dashboard server lifecycle + */ + +import express from 'express'; +import path from 'path'; +import * as fs from 'fs'; +import type { DashboardServerState } from '../types.js'; +import { getDashboardStats, getRecentAnalyses } from '../../db/index.js'; +import { + DASHBOARD_API_STATS_PATH, + DASHBOARD_CATCH_ALL_PATH, + ERROR_MESSAGES, + SUCCESS_MESSAGES, +} from '../constants.js'; + +export class DashboardService { + private state: DashboardServerState = { + httpServer: null, + port: null, + }; + + /** + * Get current server state + */ + getState(): DashboardServerState { + return { ...this.state }; + } + + /** + * Check if dashboard is running + */ + isRunning(): boolean { + return this.state.httpServer !== null && this.state.port !== null; + } + + /** + * Check if dashboard is running on specific port + */ + isRunningOnPort(port: number): boolean { + return this.isRunning() && this.state.port === port; + } + + /** + * Start dashboard server + * @throws Error if server fails to start + */ + async start(port: number, dirname: string): Promise { + // If already running on this port, do nothing + if (this.isRunningOnPort(port)) { + return; + } + + // Stop existing server if running on different port + if (this.isRunning()) { + this.stop(); + } + + return new Promise((resolve, reject) => { + const app = express(); + + // Resolve public directory + const publicDir = path.resolve(dirname, '../public'); + const srcPublicDir = path.resolve(dirname, '../../src/public'); + const staticDir = fs.existsSync(publicDir) ? publicDir : srcPublicDir; + + app.use(express.static(staticDir)); + + // API Routes + app.get(DASHBOARD_API_STATS_PATH, (req, res) => { + try { + const stats = getDashboardStats(); + const recent = getRecentAnalyses(); + res.json({ stats, recent }); + } catch (error) { + res.status(500).json({ error: 'Failed to fetch stats' }); + } + }); + + app.get(DASHBOARD_CATCH_ALL_PATH, (req, res) => { + res.sendFile(path.join(staticDir, 'index.html')); + }); + + const httpServer = app.listen(port, () => { + this.state.httpServer = httpServer; + this.state.port = port; + + console.error(SUCCESS_MESSAGES.DASHBOARD_STARTED(port)); + + // Open browser + import('open') + .then((openModule) => { + openModule.default(`http://localhost:${port}`).catch((err) => { + console.error('[MCP Server] Could not open browser:', err.message); + }); + }) + .catch((err) => { + console.error('[MCP Server] Could not import open module:', err.message); + }); + + resolve(); + }); + + httpServer.on('error', (err: any) => { + reject( + new Error( + err.code === 'EADDRINUSE' + ? ERROR_MESSAGES.DASHBOARD_PORT_IN_USE(port) + : ERROR_MESSAGES.DASHBOARD_START_FAILED(err.message) + ) + ); + }); + }); + } + + /** + * Stop dashboard server + */ + stop(): void { + if (this.state.httpServer) { + this.state.httpServer.close(); + this.state.httpServer = null; + this.state.port = null; + } + } + + /** + * Start dashboard in background (non-blocking, swallow errors) + */ + async startInBackground(port: number, dirname: string): Promise { + try { + await this.start(port, dirname); + } catch (error: any) { + console.error('[MCP Server] Failed to start dashboard:', error.message); + // Don't throw - background operation should not block analysis + } + } +} diff --git a/src/mcp/services/diff-parser.service.ts b/src/mcp/services/diff-parser.service.ts new file mode 100644 index 0000000..6c41d2f --- /dev/null +++ b/src/mcp/services/diff-parser.service.ts @@ -0,0 +1,75 @@ +/** + * Diff Parser Service + * Parses git diff output into structured file metadata + * Single Responsibility: Diff parsing and file extraction + */ + +import type { DiffFileMetadata } from '../types.js'; +import { GIT_PATTERNS } from '../constants.js'; + +export class DiffParserService { + /** + * Parse diff string into file metadata + * Extracts file paths, additions, deletions, and status + */ + static parseDiffFiles(diff: string): DiffFileMetadata[] { + const files: DiffFileMetadata[] = []; + const filePattern = new RegExp(GIT_PATTERNS.FILE_DIFF_HEADER); + let match; + + while ((match = filePattern.exec(diff)) !== null) { + const filePath = match[2] !== '/dev/null' ? match[2] : match[1]; + const isNew = match[1] === '/dev/null' || match[1].startsWith('dev/null'); + const isDeleted = match[2] === '/dev/null'; + + // Count additions and deletions for this file + const fileStart = match.index; + const nextFileMatch = filePattern.exec(diff); + const fileEnd = nextFileMatch ? nextFileMatch.index : diff.length; + filePattern.lastIndex = match.index + 1; // Reset to continue from after current match + + const fileContent = diff.substring(fileStart, fileEnd); + const additions = (fileContent.match(/^\+[^+]/gm) || []).length; + const deletions = (fileContent.match(/^-[^-]/gm) || []).length; + + files.push({ + path: filePath, + additions, + deletions, + status: isNew ? 'added' : isDeleted ? 'deleted' : 'modified', + }); + } + + return files; + } + + /** + * Calculate total additions from diff files + */ + static getTotalAdditions(files: DiffFileMetadata[]): number { + return files.reduce((sum, f) => sum + (f.additions || 0), 0); + } + + /** + * Calculate total deletions from diff files + */ + static getTotalDeletions(files: DiffFileMetadata[]): number { + return files.reduce((sum, f) => sum + (f.deletions || 0), 0); + } + + /** + * Get unique languages from file paths + */ + static getLanguagesFromFiles(files: DiffFileMetadata[]): string[] { + const extensions = new Set(); + + for (const file of files) { + const ext = file.path.split('.').pop()?.toLowerCase(); + if (ext) { + extensions.add(ext); + } + } + + return Array.from(extensions); + } +} diff --git a/src/mcp/services/formatter.service.ts b/src/mcp/services/formatter.service.ts new file mode 100644 index 0000000..7d669d2 --- /dev/null +++ b/src/mcp/services/formatter.service.ts @@ -0,0 +1,156 @@ +/** + * Formatter Service + * Formats analysis output for MCP responses + * Single Responsibility: Output formatting and presentation + */ + +import type { AnalysisOutputOptions } from '../types.js'; +import { OutputFormatter } from '../../utils/output-formatter.js'; +import { + PROMPT_STEP_EMOJIS, + DEFAULT_PROMPT_EMOJI, + DEFAULT_PROMPT_LIMIT_VERBOSE, + DEFAULT_PROMPT_LIMIT_NORMAL, + INSTRUCTIONS, + PEER_REVIEW_ERROR_CAUSES, + ERROR_MESSAGES, +} from '../constants.js'; + +export class FormatterService { + /** + * Format complete analysis output for MCP response + */ + static formatAnalysisOutput(options: AnalysisOutputOptions): string { + const lines: string[] = []; + + // Header (verbose only) + if (options.verbose) { + lines.push(`# 🤖 PR Agent Analysis\n`); + lines.push(`**Repository:** ${options.repoInfo.owner}/${options.repoInfo.name}`); + lines.push(`**Branch:** ${options.currentBranch} → ${options.baseBranch}`); + lines.push(`**PR Title:** ${options.title || 'Untitled'}`); + lines.push(`**Peer Review:** ${options.peerReviewEnabled ? '✅ Enabled' : '❌ Disabled'}`); + lines.push(`**Prompts to execute:** ${options.allPrompts.length}\n`); + lines.push(`---\n`); + } + + // Static Analysis Results + lines.push(`## 📊 Static Analysis Results\n`); + + if (options.staticAnalysis) { + const formatter = new OutputFormatter({ mode: 'markdown', verbose: options.verbose }); + const staticOutput = formatter.formatStaticAnalysis(options.staticAnalysis); + if (staticOutput) { + lines.push(staticOutput); + lines.push('\n'); + } + } + + lines.push(`---\n\n`); + + // Project Classification + if (options.projectClassification) { + const formatter = new OutputFormatter({ mode: 'markdown', verbose: options.verbose }); + const classificationOutput = formatter.formatProjectClassification(options.projectClassification); + if (classificationOutput) { + lines.push(classificationOutput); + lines.push('\n'); + } + lines.push(`---\n\n`); + } + + // DevOps Cost Estimates + lines.push(`## 💰 DevOps Cost Estimates\n`); + + if (options.devOpsCostEstimates && options.devOpsCostEstimates.length > 0) { + lines.push(`**Total Estimated Monthly Cost:** $${options.totalDevOpsCost?.toFixed(2) || '0.00'}\n`); + + options.devOpsCostEstimates.forEach(estimate => { + const emoji = estimate.confidence === 'high' ? '🟢' : estimate.confidence === 'medium' ? '🟡' : '🔴'; + lines.push(`### ${estimate.resourceType}\n`); + if (estimate.details) { + lines.push(`${emoji} ${estimate.resourceType.toUpperCase()}: ~$${estimate.estimatedNewCost.toFixed(2)}/month`); + lines.push(` ${estimate.details}\n`); + } + }); + + lines.push(`\n📊 Total Estimated Impact: ~$${options.totalDevOpsCost?.toFixed(2) || '0.00'}/month\n`); + lines.push(`\n⚠️ Estimates are approximate. Actual costs depend on usage and configuration.\n`); + } else { + lines.push(`No DevOps infrastructure changes detected.\n`); + } + + lines.push(`\n---\n`); + + // Peer Review Error (if occurred) + if (options.peerReviewEnabled && options.peerReviewError) { + lines.push(`\n---\n`); + lines.push(`## ⚠️ Peer Review Error\n`); + lines.push(ERROR_MESSAGES.PEER_REVIEW_FAILED(options.peerReviewError)); + lines.push('\n'); + lines.push(`**Possible causes:**`); + PEER_REVIEW_ERROR_CAUSES.forEach((cause) => lines.push(cause)); + lines.push('\n'); + lines.push(`Analysis will continue with base prompts only.\n`); + } + + // LLM Analysis Workflow + lines.push(`---\n`); + lines.push(`## ⚡ LLM Analysis Workflow\n`); + lines.push(INSTRUCTIONS.PROMPT_EXECUTION_WARNING); + lines.push('\n'); + lines.push(`Execute the following ${options.allPrompts.length} prompts sequentially:\n`); + + // Format each prompt + options.allPrompts.forEach((prompt, i) => { + const stepEmoji = PROMPT_STEP_EMOJIS[prompt.step] || DEFAULT_PROMPT_EMOJI; + lines.push(`### ${stepEmoji} Step ${i + 1}: ${prompt.step}\n`); + + if (options.verbose) { + lines.push(`**Instructions:** ${prompt.instructions}\n`); + } + + lines.push('**Prompt:**\n```'); + const promptLimit = options.verbose + ? DEFAULT_PROMPT_LIMIT_VERBOSE + : DEFAULT_PROMPT_LIMIT_NORMAL; + lines.push(prompt.prompt.substring(0, promptLimit)); + + if (prompt.prompt.length > promptLimit) { + lines.push('\n... (truncated for display)'); + } + lines.push('\n```\n'); + lines.push('---\n'); + }); + + // Next Steps + lines.push(`## 💾 Next Steps\n`); + lines.push(INSTRUCTIONS.NEXT_STEPS_HEADER); + INSTRUCTIONS.NEXT_STEPS(options.allPrompts.length).forEach((step) => { + lines.push(step); + }); + lines.push('\n'); + lines.push(INSTRUCTIONS.EXPECTED_TOKEN_USAGE); + + if (options.verbose) { + lines.push('\n'); + lines.push(`**Save parameters:**`); + lines.push(`- title: "${options.title || 'Untitled'}"`); + lines.push(`- repoOwner: "${options.repoInfo.owner}"`); + lines.push(`- repoName: "${options.repoInfo.name}"`); + lines.push(`- complexity: (from summary step)`); + lines.push(`- risksCount: (from risk detection step)`); + lines.push(`- risks: (from risk detection step)`); + lines.push(`- recommendations: (from summary step)`); + + if (options.peerReviewEnabled) { + lines.push(`- peerReviewEnabled: true`); + lines.push(`- ticketKey, acCompliancePercentage, etc.: (from peer review steps)`); + } + + lines.push(`\n📊 Dashboard: http://localhost:3000`); + } + + return lines.join('\n'); + } +} diff --git a/src/mcp/services/git.service.ts b/src/mcp/services/git.service.ts new file mode 100644 index 0000000..de360c3 --- /dev/null +++ b/src/mcp/services/git.service.ts @@ -0,0 +1,128 @@ +/** + * Git Service + * Handles all git operations for the MCP server + * Single Responsibility: Git repository interactions + */ + +import { execSync } from 'child_process'; +import type { RepoInfo, GitOperationOptions } from '../types.js'; +import { + DEFAULT_GIT_LOG_LIMIT, + DEFAULT_MAX_BUFFER, + GIT_PATTERNS, + DEFAULTS, +} from '../constants.js'; + +export class GitService { + /** + * Get git diff output + * @throws Error if git command fails + */ + static getGitDiff(command: string, options: GitOperationOptions = {}): string { + try { + const diff = execSync(command, { + encoding: 'utf-8', + cwd: options.cwd || process.cwd(), + maxBuffer: options.maxBuffer || DEFAULT_MAX_BUFFER, + shell: true, + } as any); + return diff.trim(); + } catch (error: any) { + throw new Error(`Failed to get diff: ${error.message}`); + } + } + + /** + * Get current branch name + */ + static getCurrentBranch(cwd?: string): string { + try { + return execSync('git rev-parse --abbrev-ref HEAD', { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + } as any).trim(); + } catch { + return DEFAULTS.BRANCH_NAME; + } + } + + /** + * Extract repository owner and name from git remote URL + */ + static getRepoInfo(cwd?: string): RepoInfo { + try { + const remoteUrl = execSync('git remote get-url origin', { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + } as any).trim(); + + // Try SSH format + const sshMatch = remoteUrl.match(GIT_PATTERNS.SSH_REMOTE); + if (sshMatch) { + return { owner: sshMatch[1], name: sshMatch[2] }; + } + + // Try HTTPS format + const httpsMatch = remoteUrl.match(GIT_PATTERNS.HTTPS_REMOTE); + if (httpsMatch) { + return { owner: httpsMatch[1], name: httpsMatch[2] }; + } + + return { owner: DEFAULTS.REPO_OWNER, name: DEFAULTS.REPO_NAME }; + } catch { + return { owner: DEFAULTS.REPO_OWNER, name: DEFAULTS.REPO_NAME }; + } + } + + /** + * Get PR title from latest commit message + */ + static getPRTitle(cwd?: string): string | undefined { + try { + const title = execSync('git log -1 --pretty=%s', { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + } as any).trim(); + return title || undefined; + } catch { + return undefined; + } + } + + /** + * Get git author from latest commit + */ + static getGitAuthor(cwd?: string): string { + try { + return execSync('git log -1 --pretty=%an', { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + } as any).trim(); + } catch { + return DEFAULTS.AUTHOR; + } + } + + /** + * Get recent commit messages for ticket extraction + */ + static getCommitMessages( + cwd?: string, + limit: number = DEFAULT_GIT_LOG_LIMIT + ): string[] { + try { + const commits = execSync(`git log --oneline -${limit}`, { + encoding: 'utf-8', + cwd: cwd || process.cwd(), + shell: true, + } as any); + return commits.trim().split('\n').filter(Boolean); + } catch { + return []; + } + } +} diff --git a/src/mcp/services/index.ts b/src/mcp/services/index.ts new file mode 100644 index 0000000..948d771 --- /dev/null +++ b/src/mcp/services/index.ts @@ -0,0 +1,11 @@ +/** + * MCP Services + * Central export point for all service classes + */ + +export { GitService } from './git.service.js'; +export { DiffParserService } from './diff-parser.service.js'; +export { TicketExtractorService } from './ticket-extractor.service.js'; +export { FormatterService } from './formatter.service.js'; +export { DashboardService } from './dashboard.service.js'; +export { PeerReviewService } from './peer-review.service.js'; diff --git a/src/mcp/services/peer-review.service.ts b/src/mcp/services/peer-review.service.ts new file mode 100644 index 0000000..673f429 --- /dev/null +++ b/src/mcp/services/peer-review.service.ts @@ -0,0 +1,91 @@ +/** + * Peer Review Service + * Orchestrates peer review analysis with Jira integration + * Single Responsibility: Peer review workflow coordination + */ + +import { execSync } from 'child_process'; +import { + createPeerReviewIntegration, + PeerReviewMode, + type PeerReviewResult, +} from '../../issue-tracker/index.js'; +import type { PeerReviewContext } from '../types.js'; +import { DiffParserService } from './diff-parser.service.js'; + +export class PeerReviewService { + /** + * Run peer review analysis in PROMPT_ONLY mode + * Returns prompts for the calling LLM to execute + */ + static async runPeerReview(context: PeerReviewContext): Promise { + try { + // Use PROMPT_ONLY mode - no LLM needed, returns prompts for calling LLM to execute + const peerReviewConfig = context.config.peerReview || {}; + const integration = createPeerReviewIntegration( + peerReviewConfig, + PeerReviewMode.PROMPT_ONLY + ); + + if (!integration.isEnabled()) { + console.error('[MCP Server] Peer Review enabled but not configured'); + if (context.verbose) { + console.error('[MCP Server] Set peerReview.useMcp=true in config'); + } + return null; + } + + // Get branch name for ticket extraction + let branchName: string | undefined; + try { + branchName = execSync('git rev-parse --abbrev-ref HEAD', { + encoding: 'utf-8', + cwd: context.workDir, + shell: true, + } as any).trim(); + } catch { + // Ignore - branch name is optional + } + + // Get commit messages for ticket extraction + let commitMessages: string[] = []; + try { + const commits = execSync('git log --oneline -10', { + encoding: 'utf-8', + cwd: context.workDir, + shell: true, + } as any); + commitMessages = commits.trim().split('\n'); + } catch { + // Ignore + } + + // Parse diff to get file info + const files = DiffParserService.parseDiffFiles(context.diff); + + console.error('[MCP Server] Running peer review analysis...'); + + // Run peer review analysis + const result = await integration.analyze({ + prTitle: context.title || 'Untitled PR', + prDescription: undefined, + branchName, + commitMessages, + diff: context.diff, + files, + prSummary: context.prAnalysisResult.summary, + prRisks: context.prAnalysisResult.overallRisks, + prComplexity: context.prAnalysisResult.overallComplexity, + }); + + console.error('[MCP Server] Peer review analysis complete'); + return result; + } catch (error: any) { + console.error('[MCP Server] Peer review failed:', error.message); + if (context.verbose) { + console.error('[MCP Server] Error details:', error.stack); + } + return null; + } + } +} diff --git a/src/mcp/services/ticket-extractor.service.ts b/src/mcp/services/ticket-extractor.service.ts new file mode 100644 index 0000000..fb67109 --- /dev/null +++ b/src/mcp/services/ticket-extractor.service.ts @@ -0,0 +1,102 @@ +/** + * Ticket Extractor Service + * Extracts ticket references from PR metadata + * Single Responsibility: Ticket identification and extraction + */ + +import type { TicketReference } from '../types.js'; + +// Default Jira ticket pattern: PROJ-123 +const DEFAULT_TICKET_PATTERN = /([A-Z][A-Z0-9]+-\d+)/g; + +export class TicketExtractorService { + /** + * Extract ticket references from all PR metadata sources + */ + static extractTicketReferences( + title: string | undefined, + branchName: string, + commitMessages: string[], + defaultProject?: string + ): TicketReference[] { + const references = new Map(); + + // Extract from title (highest confidence - 95%) + if (title) { + this.extractFromText(title, 'title', 95, references, defaultProject); + } + + // Extract from branch name (high confidence - 90%) + this.extractFromText(branchName, 'branch', 90, references, defaultProject); + + // Extract from commit messages (lower confidence - 70%) + for (const message of commitMessages) { + this.extractFromText(message, 'commit', 70, references, defaultProject); + } + + // Sort by confidence (highest first) + return Array.from(references.values()).sort( + (a, b) => b.confidence - a.confidence + ); + } + + /** + * Extract ticket keys from text using pattern matching + */ + private static extractFromText( + text: string, + source: TicketReference['source'], + baseConfidence: number, + references: Map, + defaultProject?: string + ): void { + // Reset regex state + DEFAULT_TICKET_PATTERN.lastIndex = 0; + + let match; + while ((match = DEFAULT_TICKET_PATTERN.exec(text)) !== null) { + const key = match[1].toUpperCase(); + + // If default project is set, only include tickets from that project + if (defaultProject && !key.startsWith(defaultProject)) { + continue; + } + + // Skip if we already have this reference with higher confidence + const existing = references.get(key); + if (existing && existing.confidence >= baseConfidence) { + continue; + } + + references.set(key, { + key, + source, + confidence: baseConfidence, + }); + } + } + + /** + * Get the primary (highest confidence) ticket reference + */ + static getPrimaryTicket(references: TicketReference[]): TicketReference | undefined { + return references.length > 0 ? references[0] : undefined; + } + + /** + * Check if any tickets were found + */ + static hasTickets(references: TicketReference[]): boolean { + return references.length > 0; + } + + /** + * Filter tickets by minimum confidence threshold + */ + static filterByConfidence( + references: TicketReference[], + minConfidence: number + ): TicketReference[] { + return references.filter((ref) => ref.confidence >= minConfidence); + } +} diff --git a/src/mcp/tools/analyze-tool.ts b/src/mcp/tools/analyze-tool.ts new file mode 100644 index 0000000..6255c8c --- /dev/null +++ b/src/mcp/tools/analyze-tool.ts @@ -0,0 +1,257 @@ +/** + * Analyze Tool Handler + * Handles the 'analyze' MCP tool + * Single Responsibility: Orchestrate PR analysis workflow + */ + +import { PRAnalyzerAgent } from '../../agents/pr-analyzer-agent.js'; +import { loadUserConfig, type UserConfig } from '../../cli/utils/config-loader.js'; +import { resolveDefaultBranch } from '../../utils/branch-resolver.js'; +import { ExecutionMode as ExecutionModeEnum } from '../../types/agent.types.js'; +import type { McpToolResponse, AnalysisOutputOptions } from '../types.js'; +import { + GitService, + DiffParserService, + TicketExtractorService, + FormatterService, + PeerReviewService, + DashboardService, +} from '../services/index.js'; +import { ERROR_MESSAGES, DEFAULT_DASHBOARD_PORT, DEFAULTS } from '../constants.js'; +import { analyzeDevOpsFiles } from '../../tools/devops-cost-estimator.js'; +import { parseDiff } from '../../tools/pr-analysis-tools.js'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +// __dirname workaround for ES modules +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +export interface AnalyzeToolArgs { + branch?: string; + staged?: boolean; + title?: string; + cwd?: string; + verbose?: boolean; + archDocs?: boolean; +} + +export class AnalyzeTool { + private dashboardService: DashboardService; + + constructor(dashboardService: DashboardService) { + this.dashboardService = dashboardService; + } + + async execute(args: AnalyzeToolArgs): Promise { + const workDir = args.cwd || process.cwd(); + const verbose = args.verbose || false; + + try { + // Load configuration + let config: UserConfig = {}; + try { + config = await loadUserConfig(verbose, false); + } catch (e) { + // Config not found is OK + } + + // Resolve base branch + let baseBranch = args.branch; + if (!baseBranch && !args.staged) { + try { + const branchResult = await resolveDefaultBranch({ + configBranch: config.git?.defaultBranch, + githubToken: process.env.GITHUB_TOKEN, + fallbackToGit: true, + }); + baseBranch = branchResult.branch; + } catch { + baseBranch = DEFAULTS.DEFAULT_BRANCH; + } + } + + // Get diff + let diff: string; + if (args.staged) { + diff = GitService.getGitDiff('git diff --staged', { cwd: workDir }); + } else { + diff = GitService.getGitDiff(`git diff ${baseBranch}`, { cwd: workDir }); + } + + const title = args.title || GitService.getPRTitle(workDir); + const currentBranch = GitService.getCurrentBranch(workDir); + const repoInfo = GitService.getRepoInfo(workDir); + + // Check for changes + if (!diff) { + return { + content: [ + { + type: 'text' as const, + text: ERROR_MESSAGES.NO_CHANGES(currentBranch, baseBranch || 'staged'), + }, + ], + }; + } + + // Extract ticket references + const commitMessages = GitService.getCommitMessages(workDir); + const peerReviewEnabled = config.peerReview?.enabled ?? false; + + if (verbose) { + console.error( + `[MCP Server] Config loaded: peerReview.enabled=${peerReviewEnabled}, archDocs=${args.archDocs !== false}` + ); + } + + const ticketRefs = TicketExtractorService.extractTicketReferences( + title, + currentBranch, + commitMessages, + config.peerReview?.defaultProject + ); + + // Create PRAnalyzerAgent in PROMPT_ONLY mode + const agent = new PRAnalyzerAgent({ mode: ExecutionModeEnum.PROMPT_ONLY }); + + // Run analysis to get prompts (no LLM execution) + const useArchDocs = args.archDocs !== false; + if (verbose) { + console.error('[MCP Server] Building analysis prompts in PROMPT_ONLY mode...'); + } + + const analysisResult = await agent.analyze( + diff, + title, + { summary: true, risks: true, complexity: true }, + { + useArchDocs, + repoPath: workDir, + language: config.analysis?.language, + framework: config.analysis?.framework, + enableStaticAnalysis: config.analysis?.enableStaticAnalysis !== false, + } + ); + + // DETERMINISTIC ANALYSIS: DevOps cost estimation (runs even in PROMPT_ONLY mode) + let devOpsCostEstimates; + let totalDevOpsCost = 0; + + const parsedFiles = parseDiff(diff); + const filesForCostAnalysis = parsedFiles.map((f: any) => ({ path: f.path, diff: f.diff })); + + if (verbose) { + console.error(`[MCP Server] Parsed ${parsedFiles.length} files for cost analysis`); + console.error(`[MCP Server] Sample file paths: ${parsedFiles.slice(0, 3).map((f: any) => f.path).join(', ')}`); + } + + const costAnalysis = analyzeDevOpsFiles(filesForCostAnalysis); + + if (verbose) { + console.error(`[MCP Server] Cost analysis complete: hasDevOpsChanges=${costAnalysis.hasDevOpsChanges}, estimates=${costAnalysis.estimates.length}`); + } + + if (costAnalysis.hasDevOpsChanges && costAnalysis.estimates.length > 0) { + devOpsCostEstimates = costAnalysis.estimates; + totalDevOpsCost = costAnalysis.totalEstimatedCost; + console.error(`[MCP Server] DevOps costs: ${costAnalysis.estimates.length} resources (~$${totalDevOpsCost.toFixed(2)}/month)`); + } else if (verbose) { + console.error(`[MCP Server] No DevOps costs found`); + } + + if (verbose) { + console.error('[MCP Server] Analysis prompts built'); + console.error(` - mode: ${analysisResult.mode}`); + console.error( + ` - prompt count: ${analysisResult.mode === 'prompt_only' ? analysisResult.prompts.length : 'N/A'}` + ); + console.error(` - peer review: ${peerReviewEnabled ? 'enabled' : 'disabled'}`); + } + + // Type guard + if (analysisResult.mode !== 'prompt_only') { + throw new Error('Expected prompt-only result in MCP mode'); + } + + // Get peer review prompts if enabled + let peerReviewError: string | undefined; + if (peerReviewEnabled) { + try { + const peerReviewResult = await PeerReviewService.runPeerReview({ + config, + diff, + title, + prAnalysisResult: analysisResult as any, + verbose, + workDir, + }); + + if ( + peerReviewResult && + peerReviewResult.mode === 'prompt_only' && + peerReviewResult.promptOnlyResult + ) { + analysisResult.prompts.push(...peerReviewResult.promptOnlyResult.prompts); + console.error(` - Peer review prompts: ${peerReviewResult.promptOnlyResult.prompts.length}`); + } else if (peerReviewResult && peerReviewResult.error) { + peerReviewError = peerReviewResult.error; + console.error(`[MCP Server] Peer review failed: ${peerReviewError}`); + } + } catch (error: any) { + peerReviewError = error.message; + console.error('[MCP Server] Peer review prompt building failed:', error.message); + if (verbose) { + console.error(error.stack); + } + } + } + + // Format output + const outputOptions: AnalysisOutputOptions = { + verbose, + peerReviewEnabled, + peerReviewError, + allPrompts: analysisResult.prompts, + staticAnalysis: analysisResult.staticAnalysis, + devOpsCostEstimates, + totalDevOpsCost, + projectClassification: (analysisResult as any).projectClassification, + repoInfo, + currentBranch, + baseBranch, + title, + }; + + if (verbose && devOpsCostEstimates) { + console.error(`[MCP Server] Passing ${devOpsCostEstimates.length} cost estimates to formatter:`); + devOpsCostEstimates.forEach((est, i) => { + console.error(` [${i}] ${est.resourceType}: cost=$${est.estimatedNewCost}, details="${est.details}"`); + }); + } + + const outputText = FormatterService.formatAnalysisOutput(outputOptions); + + // Start dashboard in background + await this.dashboardService.startInBackground(DEFAULT_DASHBOARD_PORT, __dirname); + + return { + content: [ + { + type: 'text' as const, + text: outputText, + }, + ], + }; + } catch (error: any) { + return { + content: [ + { + type: 'text' as const, + text: ERROR_MESSAGES.ANALYSIS_FAILED(error.message), + }, + ], + }; + } + } +} diff --git a/src/mcp/tools/dashboard-tool.ts b/src/mcp/tools/dashboard-tool.ts new file mode 100644 index 0000000..716e377 --- /dev/null +++ b/src/mcp/tools/dashboard-tool.ts @@ -0,0 +1,59 @@ +/** + * Dashboard Tool Handler + * Handles the 'dashboard' MCP tool + * Single Responsibility: Start/manage dashboard server + */ + +import type { McpToolResponse } from '../types.js'; +import { DashboardService } from '../services/index.js'; +import { ERROR_MESSAGES, DEFAULT_DASHBOARD_PORT } from '../constants.js'; + +export interface DashboardToolArgs { + port?: number; +} + +export class DashboardTool { + private dashboardService: DashboardService; + + constructor(dashboardService: DashboardService) { + this.dashboardService = dashboardService; + } + + async execute(args: DashboardToolArgs, dirname: string): Promise { + const targetPort = args.port || DEFAULT_DASHBOARD_PORT; + + // Check if already running on this port + if (this.dashboardService.isRunningOnPort(targetPort)) { + return { + content: [ + { + type: 'text' as const, + text: ERROR_MESSAGES.DASHBOARD_ALREADY_RUNNING(targetPort), + }, + ], + }; + } + + try { + await this.dashboardService.start(targetPort, dirname); + + return { + content: [ + { + type: 'text' as const, + text: `✅ Dashboard started successfully!\n\n📊 Access at: http://localhost:${targetPort}\n\nView PR analysis history, statistics, and insights.`, + }, + ], + }; + } catch (error: any) { + return { + content: [ + { + type: 'text' as const, + text: `❌ Failed to start dashboard: ${error.message}`, + }, + ], + }; + } + } +} diff --git a/src/mcp/tools/index.ts b/src/mcp/tools/index.ts new file mode 100644 index 0000000..510295d --- /dev/null +++ b/src/mcp/tools/index.ts @@ -0,0 +1,8 @@ +/** + * MCP Tools + * Central export point for all tool handlers + */ + +export { AnalyzeTool, type AnalyzeToolArgs } from './analyze-tool.js'; +export { SaveResultsTool, type SaveResultsToolArgs } from './save-results-tool.js'; +export { DashboardTool, type DashboardToolArgs } from './dashboard-tool.js'; diff --git a/src/mcp/tools/save-results-tool.ts b/src/mcp/tools/save-results-tool.ts new file mode 100644 index 0000000..b290dbd --- /dev/null +++ b/src/mcp/tools/save-results-tool.ts @@ -0,0 +1,97 @@ +/** + * Save Analysis Results Tool Handler + * Handles the 'saveAnalysisResults' MCP tool + * Single Responsibility: Persist analysis results to database + */ + +import { saveAnalysis } from '../../db/index.js'; +import type { McpToolResponse } from '../types.js'; +import { SUCCESS_MESSAGES, ERROR_MESSAGES, DEFAULT_DASHBOARD_PORT } from '../constants.js'; + +export interface SaveResultsToolArgs { + prNumber?: number; + title: string; + repoOwner?: string; + repoName?: string; + author?: string; + complexity: number; + risksCount: number; + risks: string[]; + recommendations: string[]; + projectClassification?: string; + peerReviewEnabled?: boolean; + ticketKey?: string; + ticketQualityScore?: number; + ticketQualityTier?: string; + acCompliancePercentage?: number; + acRequirementsMet?: number; + acRequirementsTotal?: number; + peerReviewVerdict?: string; + peerReviewBlockers?: string[]; + peerReviewWarnings?: string[]; + implementationCompleteness?: number; + qualityScore?: number; + devopsCostMonthly?: number; + devopsResources?: string; +} + +export class SaveResultsTool { + private dashboardPort: number; + + constructor(dashboardPort: number = DEFAULT_DASHBOARD_PORT) { + this.dashboardPort = dashboardPort; + } + + async execute(args: SaveResultsToolArgs): Promise { + try { + saveAnalysis({ + pr_number: args.prNumber || Math.floor(Date.now() / 1000) % 100000, + repo_owner: args.repoOwner || 'local', + repo_name: args.repoName || 'unknown', + author: args.author || 'unknown', + title: args.title, + complexity: args.complexity, + risks_count: args.risksCount, + risks: JSON.stringify(args.risks), + recommendations: JSON.stringify(args.recommendations), + project_classification: args.projectClassification, + peer_review_enabled: args.peerReviewEnabled ? 1 : 0, + ticket_key: args.ticketKey, + ticket_quality_score: args.ticketQualityScore, + ticket_quality_tier: args.ticketQualityTier, + ac_compliance_percentage: args.acCompliancePercentage, + ac_requirements_met: args.acRequirementsMet, + ac_requirements_total: args.acRequirementsTotal, + peer_review_verdict: args.peerReviewVerdict, + peer_review_blockers: args.peerReviewBlockers + ? JSON.stringify(args.peerReviewBlockers) + : undefined, + peer_review_warnings: args.peerReviewWarnings + ? JSON.stringify(args.peerReviewWarnings) + : undefined, + implementation_completeness: args.implementationCompleteness, + quality_score: args.qualityScore, + devops_cost_monthly: args.devopsCostMonthly, + devops_resources: args.devopsResources, + }); + + return { + content: [ + { + type: 'text' as const, + text: SUCCESS_MESSAGES.ANALYSIS_SAVED(this.dashboardPort), + }, + ], + }; + } catch (error: any) { + return { + content: [ + { + type: 'text' as const, + text: ERROR_MESSAGES.SAVE_FAILED(error.message), + }, + ], + }; + } + } +} diff --git a/src/mcp/types.ts b/src/mcp/types.ts new file mode 100644 index 0000000..bd982fa --- /dev/null +++ b/src/mcp/types.ts @@ -0,0 +1,110 @@ +/** + * MCP Server Types + * Type definitions specific to the MCP server implementation + */ + +import type { AnalysisPrompt } from '../types/agent.types.js'; + +/** + * Repository information extracted from git remote + */ +export interface RepoInfo { + owner: string; + name: string; +} + +/** + * Git diff file metadata + */ +export interface DiffFileMetadata { + path: string; + additions: number; + deletions: number; + status: 'added' | 'deleted' | 'modified'; +} + +/** + * Ticket reference extracted from PR metadata + */ +export interface TicketReference { + key: string; + source: 'title' | 'branch' | 'commit' | 'description'; + confidence: number; +} + +/** + * Dashboard statistics + */ +export interface DashboardStats { + totalAnalyses: number; + averageComplexity: number; + criticalRisks: number; + recentActivity: Array<{ + date: string; + count: number; + }>; +} + +/** + * MCP Tool Response format + * Matches the MCP SDK's expected return type with index signature + */ +export interface McpToolResponse { + [x: string]: unknown; + content: Array<{ + type: 'text'; + text: string; + }>; +} + +/** + * Analysis output formatting options + */ +export interface AnalysisOutputOptions { + verbose: boolean; + peerReviewEnabled: boolean; + peerReviewError?: string; + allPrompts: AnalysisPrompt[]; + staticAnalysis?: any; + devOpsCostEstimates?: Array<{ + resource: string; + resourceType: string; + estimatedNewCost: number; + confidence: 'high' | 'medium' | 'low'; + details?: string; + }>; + totalDevOpsCost?: number; + projectClassification?: any; + repoInfo: RepoInfo; + currentBranch: string; + baseBranch?: string; + title?: string; +} + +/** + * Dashboard server state + */ +export interface DashboardServerState { + httpServer: any | null; + port: number | null; +} + +/** + * Git operation options + */ +export interface GitOperationOptions { + cwd?: string; + maxBuffer?: number; +} + +/** + * Peer review analysis context + */ +export interface PeerReviewContext { + config: any; + diff: string; + title: string | undefined; + prAnalysisResult: any; + verbose: boolean; + workDir: string; +} diff --git a/src/providers/anthropic.provider.ts b/src/providers/anthropic.provider.ts index bdbb9c3..ec58e2c 100644 --- a/src/providers/anthropic.provider.ts +++ b/src/providers/anthropic.provider.ts @@ -30,7 +30,8 @@ export class AnthropicProvider implements ILLMProvider { apiKey: this.apiKey, modelName: config.model || this.getDefaultModel(), temperature: config.temperature ?? 0.2, - maxTokens: config.maxTokens ?? 4000, + maxTokens: config.maxTokens ?? 50000, + streaming: true, }); } } diff --git a/src/providers/google.provider.ts b/src/providers/google.provider.ts index 075e6af..5331d2d 100644 --- a/src/providers/google.provider.ts +++ b/src/providers/google.provider.ts @@ -30,7 +30,7 @@ export class GoogleProvider implements ILLMProvider { apiKey: this.apiKey, model: config.model || this.getDefaultModel(), temperature: config.temperature ?? 0.2, - maxOutputTokens: config.maxTokens ?? 4000, + maxOutputTokens: config.maxTokens ?? 50000, }); } } diff --git a/src/providers/index.ts b/src/providers/index.ts index 53e97cd..3533f79 100644 --- a/src/providers/index.ts +++ b/src/providers/index.ts @@ -3,4 +3,5 @@ export * from './provider.factory.js'; export * from './anthropic.provider.js'; export * from './openai.provider.js'; export * from './google.provider.js'; +export * from './zhipu.provider.js'; diff --git a/src/providers/openai.provider.ts b/src/providers/openai.provider.ts index f83a767..f3f37f1 100644 --- a/src/providers/openai.provider.ts +++ b/src/providers/openai.provider.ts @@ -30,7 +30,7 @@ export class OpenAIProvider implements ILLMProvider { apiKey: this.apiKey, modelName: config.model || this.getDefaultModel(), temperature: config.temperature ?? 0.2, - maxTokens: config.maxTokens ?? 4000, + maxTokens: config.maxTokens ?? 50000, }); } } diff --git a/src/providers/provider.factory.ts b/src/providers/provider.factory.ts index ee7762d..50f7f6c 100644 --- a/src/providers/provider.factory.ts +++ b/src/providers/provider.factory.ts @@ -2,9 +2,10 @@ import { ILLMProvider, ProviderConfig } from './provider.interface.js'; import { AnthropicProvider } from './anthropic.provider.js'; import { OpenAIProvider } from './openai.provider.js'; import { GoogleProvider } from './google.provider.js'; +import { ZhipuProvider } from './zhipu.provider.js'; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; -export type SupportedProvider = 'anthropic' | 'openai' | 'google'; +export type SupportedProvider = 'anthropic' | 'openai' | 'google' | 'zhipu'; export interface ProviderOptions { provider?: SupportedProvider; @@ -48,8 +49,11 @@ export class ProviderFactory { case 'google': provider = new GoogleProvider(apiKey); break; + case 'zhipu': + provider = new ZhipuProvider(apiKey); + break; default: - throw new Error(`Unsupported provider: ${providerName}. Supported: anthropic, openai, google`); + throw new Error(`Unsupported provider: ${providerName}. Supported: anthropic, openai, google, zhipu`); } // Cache the provider if no specific API key was provided @@ -109,6 +113,7 @@ export class ProviderFactory { const normalized = name.toLowerCase(); if (normalized === 'claude') return 'anthropic'; if (normalized === 'gemini') return 'google'; + if (normalized === 'glm' || normalized === 'zhipuai') return 'zhipu'; return normalized; } @@ -116,7 +121,7 @@ export class ProviderFactory { * Get list of available providers */ public static getAvailableProviders(): SupportedProvider[] { - return ['anthropic', 'openai', 'google']; + return ['anthropic', 'openai', 'google', 'zhipu']; } } diff --git a/src/providers/zhipu.provider.ts b/src/providers/zhipu.provider.ts new file mode 100644 index 0000000..fb0f9c3 --- /dev/null +++ b/src/providers/zhipu.provider.ts @@ -0,0 +1,42 @@ +import { ChatAnthropic } from '@langchain/anthropic'; +import { BaseChatModel } from '@langchain/core/language_models/chat_models'; +import { ILLMProvider, ProviderConfig } from './provider.interface.js'; + +/** + * Zhipu AI (智谱AI) provider implementation + * Uses Anthropic-compatible API endpoint + * Docs: https://docs.z.ai/ + */ +export class ZhipuProvider implements ILLMProvider { + public readonly name = 'zhipu'; + private readonly apiKey: string; + private readonly baseUrl = 'https://api.z.ai/api/anthropic'; + + constructor(apiKey?: string) { + this.apiKey = apiKey || process.env.ZHIPU_API_KEY || ''; + } + + public isConfigured(): boolean { + return !!this.apiKey; + } + + public getDefaultModel(): string { + // GLM-4.7 via Z.AI's Anthropic-compatible API + return 'glm-4.7'; + } + + public getChatModel(config: ProviderConfig = {}): BaseChatModel { + if (!this.isConfigured()) { + throw new Error('Zhipu API key is not configured. Set ZHIPU_API_KEY environment variable.'); + } + + return new ChatAnthropic({ + anthropicApiKey: this.apiKey, + anthropicApiUrl: this.baseUrl, + modelName: config.model || this.getDefaultModel(), + temperature: config.temperature ?? 0.2, + maxTokens: config.maxTokens ?? 50000, + streaming: true, + }); + } +} diff --git a/src/public/dashboard.js b/src/public/dashboard.js new file mode 100644 index 0000000..6b6cd12 --- /dev/null +++ b/src/public/dashboard.js @@ -0,0 +1,438 @@ +document.addEventListener('DOMContentLoaded', async () => { + // Theme Toggle Logic + const themeToggleBtn = document.getElementById('theme-toggle'); + + function applyTheme(isDark) { + if (isDark) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + } + + // Check preference + const isDark = localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches); + applyTheme(isDark); + + themeToggleBtn.addEventListener('click', () => { + const isCurrentlyDark = document.documentElement.classList.contains('dark'); + localStorage.theme = isCurrentlyDark ? 'light' : 'dark'; + applyTheme(!isCurrentlyDark); + // Reload to update charts colors if necessary + location.reload(); + }); + + try { + const response = await fetch('/dashboard/api/stats'); + const data = await response.json(); + + if (data.error) { + console.error('Error fetching data:', data.error); + return; + } + + renderStats(data.stats); + renderCharts(data.stats); + renderTable(data.recent); + + } catch (error) { + console.error('Failed to load dashboard data:', error); + } +}); + +function formatCurrency(amount) { + return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 4 }).format(amount); +} + +function formatTokens(tokens) { + if (tokens >= 1000000) { + return (tokens / 1000000).toFixed(1) + 'M'; + } else if (tokens >= 1000) { + return (tokens / 1000).toFixed(1) + 'K'; + } + return tokens.toString(); +} + +function renderStats(stats) { + document.getElementById('stats-total-prs').textContent = stats.totalPRs; + document.getElementById('stats-success-rate').textContent = `${stats.successRate.toFixed(1)}%`; + document.getElementById('stats-avg-complexity').textContent = stats.avgComplexity.toFixed(1); + + // Dashboard improvements (PR #13) - Unit tests created & terraform cost + if (stats.metrics) { + document.getElementById('stats-tests-created').textContent = stats.metrics.testsCreated; + const cost = formatCurrency(stats.metrics.terraformCost); + document.getElementById('stats-terraform-cost').textContent = cost; + } + + // DevOps/Infrastructure Cost Stats Rendering (v0.2.0) + if (stats.devOpsCosts) { + document.getElementById('stats-devops-cost').textContent = formatCurrency(stats.devOpsCosts.totalMonthlyEstimate || 0) + '/mo'; + document.getElementById('stats-devops-count').textContent = stats.devOpsCosts.analysesWithDevOps || 0; + document.getElementById('stats-test-suggestions').textContent = stats.devOpsCosts.testSuggestionStats?.totalSuggestions || 0; + + // Use average coverage from both metrics and devOpsCosts (prefer devOpsCosts as it's more specific) + const avgCoverage = stats.devOpsCosts.coverageStats?.averageCoverage || stats.metrics?.avgCoverage || 0; + document.getElementById('stats-avg-coverage').textContent = avgCoverage > 0 ? `${avgCoverage.toFixed(1)}%` : 'N/A'; + } else { + document.getElementById('stats-devops-cost').textContent = '$0.00/mo'; + document.getElementById('stats-devops-count').textContent = '0'; + document.getElementById('stats-test-suggestions').textContent = '0'; + + // Fallback to metrics if devOpsCosts not available + const avgCoverage = stats.metrics?.avgCoverage || 0; + document.getElementById('stats-avg-coverage').textContent = avgCoverage > 0 ? `${avgCoverage.toFixed(1)}%` : 'N/A'; + } + + // Render Recommendations + const recList = document.getElementById('recommendations-list'); + recList.innerHTML = ''; + + if (stats.commonRecommendations && stats.commonRecommendations.length > 0) { + stats.commonRecommendations.forEach(item => { + const div = document.createElement('div'); + div.className = 'flex items-start'; + div.innerHTML = ` + + ${item.count} + +

${item.text}

+ `; + recList.appendChild(div); + }); + } else { + recList.innerHTML = '

No recurring recommendations yet.

'; + } +} + +function renderCharts(stats) { + // Creators Chart + const creatorsCtx = document.getElementById('chart-creators').getContext('2d'); + + // Prepare data + const labels = stats.perCreator.map(c => c.author); + const counts = stats.perCreator.map(c => c.count); + const complex = stats.perCreator.map(c => c.avg_complexity); + + new Chart(creatorsCtx, { + type: 'bar', + data: { + labels: labels, + datasets: [ + { + label: 'PR Count', + data: counts, + backgroundColor: 'rgba(59, 130, 246, 0.5)', + borderColor: 'rgb(59, 130, 246)', + borderWidth: 1, + yAxisID: 'y' + }, + { + label: 'Avg Complexity', + data: complex, + type: 'line', + borderColor: 'rgb(234, 179, 8)', + borderWidth: 2, + pointBackgroundColor: 'rgb(234, 179, 8)', + yAxisID: 'y1' + } + ] + }, + options: { + responsive: true, + interaction: { + mode: 'index', + intersect: false, + }, + scales: { + y: { + beginAtZero: true, + title: { display: true, text: 'Number of PRs' } + }, + y1: { + type: 'linear', + display: true, + position: 'right', + title: { display: true, text: 'Complexity (1-5)' }, + min: 0, + max: 5, + grid: { + drawOnChartArea: false, + }, + } + } + } + }); + + // JIRA Compliance Chart + // Default to 0s if not present (placeholder) + const jiraData = stats.jiraCompliance || { satisfied: 0, missed: 0 }; + const jiraCtx = document.getElementById('chart-jira').getContext('2d'); + + new Chart(jiraCtx, { + type: 'bar', + data: { + labels: ['Satisfied Review', 'Missed Requirements'], + datasets: [{ + label: 'PR Count', + data: [jiraData.satisfied, jiraData.missed], + backgroundColor: [ + 'rgba(34, 197, 94, 0.6)', // Green + 'rgba(239, 68, 68, 0.6)' // Red + ], + borderColor: [ + 'rgb(34, 197, 94)', + 'rgb(239, 68, 68)' + ], + borderWidth: 1 + }] + }, + options: { + indexAxis: 'y', + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + beginAtZero: true, + ticks: { stepSize: 1 }, + title: { display: true, text: 'Number of PRs' } + } + }, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + label: function(context) { + return `${context.dataset.label}: ${context.raw}`; + } + } + } + } + } + }); + + // Trend Chart + const trendCtx = document.getElementById('chart-trend').getContext('2d'); + + const trendLabels = stats.qualityTrend.map(t => t.date); + const trendData = stats.qualityTrend.map(t => t.avg_complexity); + + new Chart(trendCtx, { + type: 'line', + data: { + labels: trendLabels, + datasets: [{ + label: 'Avg Daily Complexity', + data: trendData, + borderColor: 'rgb(79, 70, 229)', + backgroundColor: 'rgba(79, 70, 229, 0.1)', + tension: 0.3, + fill: true + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 5, + title: { display: true, text: 'Complexity Score' } + } + } + } + }); + + // Complexity Chart + const complexityCtx = document.getElementById('chart-complexity').getContext('2d'); + new Chart(complexityCtx, { + type: 'doughnut', + data: { + labels: ['Low (1-2) - Good', 'Medium (3-4) - Watch', 'High (5) - Risky'], + datasets: [{ + data: stats.complexityDistribution || [0, 0, 0], + backgroundColor: [ + 'rgb(34, 197, 94)', // Green + 'rgb(234, 179, 8)', // Yellow + 'rgb(239, 68, 68)' // Red + ], + borderWidth: 0 + }] + }, + options: { + cutout: '60%', + plugins: { + legend: { + position: 'bottom' + } + } + } + }); + + // DevOps Resource Types Chart (v0.2.0) + if (stats.devOpsCosts && stats.devOpsCosts.resourceTypes && Object.keys(stats.devOpsCosts.resourceTypes).length > 0) { + const devOpsCtx = document.getElementById('chart-devops-resources').getContext('2d'); + const resourceLabels = Object.keys(stats.devOpsCosts.resourceTypes); + const resourceData = Object.values(stats.devOpsCosts.resourceTypes); + + new Chart(devOpsCtx, { + type: 'doughnut', + data: { + labels: resourceLabels.map(r => r.toUpperCase()), + datasets: [{ + data: resourceData, + backgroundColor: [ + 'rgb(16, 185, 129)', // Green (EC2) + 'rgb(245, 158, 11)', // Amber (Lambda) + 'rgb(59, 130, 246)', // Blue (S3) + 'rgb(139, 92, 246)', // Purple (RDS) + 'rgb(236, 72, 153)', // Pink (ECS) + 'rgb(244, 63, 94)', // Rose (Others) + ], + borderWidth: 0 + }] + }, + options: { + cutout: '60%', + plugins: { + legend: { + position: 'bottom' + }, + tooltip: { + callbacks: { + label: function(context) { + return `${context.label}: ${context.parsed} PRs`; + } + } + } + } + } + }); + } else { + // Show placeholder when no DevOps data + const devOpsContainer = document.getElementById('chart-devops-resources'); + if (devOpsContainer) { + devOpsContainer.parentElement.innerHTML = '

No DevOps/IaC changes detected yet.

'; + } + } + + // DevOps Cost Trend Chart (v0.2.0) + if (stats.devOpsCosts && stats.devOpsCosts.costTrend && stats.devOpsCosts.costTrend.length > 0) { + const costTrendCtx = document.getElementById('chart-cost-trend').getContext('2d'); + const trendLabels = stats.devOpsCosts.costTrend.map(t => t.date); + const trendData = stats.devOpsCosts.costTrend.map(t => t.cost); + + new Chart(costTrendCtx, { + type: 'line', + data: { + labels: trendLabels, + datasets: [{ + label: 'Daily DevOps Cost', + data: trendData, + borderColor: 'rgb(16, 185, 129)', + backgroundColor: 'rgba(16, 185, 129, 0.1)', + tension: 0.3, + fill: true + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + title: { display: true, text: 'Cost ($)' }, + ticks: { + callback: function(value) { + return '$' + value.toFixed(2); + } + } + }, + x: { + title: { display: true, text: 'Date' } + } + }, + plugins: { + legend: { + display: true, + position: 'top' + }, + tooltip: { + callbacks: { + label: function(context) { + return 'Cost: $' + context.parsed.y.toFixed(2); + } + } + } + } + } + }); + } else { + // Show placeholder when no cost trend data + const costTrendContainer = document.getElementById('chart-cost-trend'); + if (costTrendContainer) { + costTrendContainer.parentElement.innerHTML = '

No cost trend data available yet.

'; + } + } +} + +function renderTable(recent) { + const tbody = document.getElementById('table-recent-body'); + tbody.innerHTML = ''; + + recent.forEach(row => { + const tr = document.createElement('tr'); + + // Format Date + const date = new Date(row.timestamp).toLocaleDateString(); + + // Format DevOps Cost (v0.2.0) + const cost = row.devops_cost_monthly ? formatCurrency(row.devops_cost_monthly) + '/mo' : '-'; + let costTitle = ''; + if (row.devops_resources) { + try { + const resources = JSON.parse(row.devops_resources); + costTitle = resources.map(r => r.resourceType).join(', '); + } catch (e) { + costTitle = 'AWS infrastructure cost estimate'; + } + } + + // Construct link URL - prefer Jira ticket if available, otherwise GitHub PR + let linkUrl, linkText; + if (row.ticket_key) { + // Jira ticket link (assumes ipanovritech.atlassian.net, can be made configurable) + linkUrl = `https://ipanovritech.atlassian.net/browse/${row.ticket_key}`; + linkText = row.ticket_key; + } else { + // GitHub PR link + linkUrl = `https://github.com/${row.repo_owner}/${row.repo_name}/pull/${row.pr_number}`; + linkText = `#${row.pr_number}`; + } + + tr.innerHTML = ` + + + ${linkText} + + + ${row.repo_owner}/${row.repo_name} + ${row.author} + + + ${row.complexity}/5 + + + ${row.risks_count} + ${cost} + ${date} + `; + tbody.appendChild(tr); + }); +} + +function getComplexityColor(score) { + if (score < 3) return 'bg-green-100 text-green-800'; + if (score < 5) return 'bg-yellow-100 text-yellow-800'; + return 'bg-red-100 text-red-800'; +} diff --git a/src/public/index.html b/src/public/index.html new file mode 100644 index 0000000..516a0f2 --- /dev/null +++ b/src/public/index.html @@ -0,0 +1,284 @@ + + + + + + PeeR-Agent Dashboard + + + + + + + + + +
+ +
+ +
+
+
+
+ +
+
+
+
Total PRs
+
-
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
Success Rate
+
-
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
Avg Complexity
+
-
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
Tests Created
+
0
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
Infra Cost
+
$0
+
+
+
+
+
+
+ + +
+

JIRA Requirements Compliance

+
+ +
+
+ + +
+

Code Quality Trend (Daily Avg Complexity)

+
+ +
+
+ +
+ +
+

PR Activity by Creator

+ +
+ + +
+

Complexity Distribution

+ +
+
+ +
+ +
+

Most Requested Changes

+
+ +
+
+ + +
+

Detected DevOps Resources

+ +
+
+ + +
+ +
+
+
+
+ +
+
+
+
DevOps Cost/mo
+
-
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
IaC Changes
+
-
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
Test Suggestions
+
-
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
Avg Coverage
+
-
+
+
+
+
+
+
+ + +
+

Daily Cost Trend

+
+ +
+
+ + + +
+
+

Recent Analysis

+
+
+ + + + + + + + + + + + + + + +
PRRepoAuthorComplexityRisksDevOps CostDate
+
+
+
+ + + + diff --git a/src/tools/coverage-analyzer.ts b/src/tools/coverage-analyzer.ts new file mode 100644 index 0000000..7023fc2 --- /dev/null +++ b/src/tools/coverage-analyzer.ts @@ -0,0 +1,623 @@ +/** + * Coverage Analyzer Tool for PR Analysis + * Integrates Istanbul/nyc coverage data and ESLint static analysis + * to provide coverage-based test suggestions + */ + +import { exec } from 'child_process'; +import { promisify } from 'util'; +import fs from 'fs'; +import path from 'path'; + +const execAsync = promisify(exec); + +// ========== Types ========== + +export interface CoverageMetrics { + statements: { covered: number; total: number; pct: number }; + branches: { covered: number; total: number; pct: number }; + functions: { covered: number; total: number; pct: number }; + lines: { covered: number; total: number; pct: number }; +} + +export interface FileCoverage { + path: string; + metrics: CoverageMetrics; + uncoveredLines: number[]; + uncoveredBranches: string[]; + uncoveredFunctions: string[]; +} + +export interface UncoveredCode { + filePath: string; + functionName?: string; + lineRange: { start: number; end: number }; + type: 'function' | 'branch' | 'statement' | 'line'; + suggestion?: string; +} + +export interface CoverageAnalysis { + overall: CoverageMetrics; + files: FileCoverage[]; + uncoveredCode: UncoveredCode[]; + timestamp: string; + hasReport: boolean; +} + +export interface StaticAnalysisIssue { + filePath: string; + line: number; + column: number; + severity: 'error' | 'warning' | 'info'; + ruleId: string; + message: string; + suggestion?: string; +} + +export interface StaticAnalysis { + issues: StaticAnalysisIssue[]; + summary: { + errors: number; + warnings: number; + info: number; + fixable: number; + }; + hasResults: boolean; +} + +// ========== Coverage Report Detection ========== + +/** + * Detect if a coverage report exists and its format + */ +export function detectCoverageReport(repoPath: string = '.'): { + found: boolean; + format: 'lcov' | 'json' | 'clover' | 'none'; + path: string | null; +} { + const coverageDir = path.join(repoPath, 'coverage'); + + // Check for common coverage report locations + const lcovPath = path.join(coverageDir, 'lcov.info'); + const jsonPath = path.join(coverageDir, 'coverage-final.json'); + const jsonSummaryPath = path.join(coverageDir, 'coverage-summary.json'); + const cloverPath = path.join(coverageDir, 'clover.xml'); + + if (fs.existsSync(jsonSummaryPath)) { + return { found: true, format: 'json', path: jsonSummaryPath }; + } + if (fs.existsSync(jsonPath)) { + return { found: true, format: 'json', path: jsonPath }; + } + if (fs.existsSync(lcovPath)) { + return { found: true, format: 'lcov', path: lcovPath }; + } + if (fs.existsSync(cloverPath)) { + return { found: true, format: 'clover', path: cloverPath }; + } + + return { found: false, format: 'none', path: null }; +} + +/** + * Parse coverage-summary.json (Istanbul/nyc format) + */ +export function parseCoverageJson(reportPath: string): CoverageAnalysis { + try { + const content = fs.readFileSync(reportPath, 'utf-8'); + const data = JSON.parse(content); + + const files: FileCoverage[] = []; + const uncoveredCode: UncoveredCode[] = []; + + // Extract overall metrics + const overall = data.total ? { + statements: { + covered: data.total.statements?.covered || 0, + total: data.total.statements?.total || 0, + pct: data.total.statements?.pct || 0, + }, + branches: { + covered: data.total.branches?.covered || 0, + total: data.total.branches?.total || 0, + pct: data.total.branches?.pct || 0, + }, + functions: { + covered: data.total.functions?.covered || 0, + total: data.total.functions?.total || 0, + pct: data.total.functions?.pct || 0, + }, + lines: { + covered: data.total.lines?.covered || 0, + total: data.total.lines?.total || 0, + pct: data.total.lines?.pct || 0, + }, + } : createEmptyMetrics(); + + // Process each file + for (const [filePath, fileData] of Object.entries(data)) { + if (filePath === 'total') continue; + + const fd = fileData as any; + const metrics: CoverageMetrics = { + statements: { + covered: fd.statements?.covered || 0, + total: fd.statements?.total || 0, + pct: fd.statements?.pct || 0, + }, + branches: { + covered: fd.branches?.covered || 0, + total: fd.branches?.total || 0, + pct: fd.branches?.pct || 0, + }, + functions: { + covered: fd.functions?.covered || 0, + total: fd.functions?.total || 0, + pct: fd.functions?.pct || 0, + }, + lines: { + covered: fd.lines?.covered || 0, + total: fd.lines?.total || 0, + pct: fd.lines?.pct || 0, + }, + }; + + // Identify uncovered items + const uncoveredLines: number[] = []; + const uncoveredBranches: string[] = []; + const uncoveredFunctions: string[] = []; + + // For low coverage files, add to uncovered code suggestions + if (metrics.lines.pct < 50) { + uncoveredCode.push({ + filePath, + type: 'line', + lineRange: { start: 1, end: metrics.lines.total }, + suggestion: `File has ${metrics.lines.pct.toFixed(1)}% line coverage. Consider adding tests.`, + }); + } + + if (metrics.functions.pct < 50) { + uncoveredCode.push({ + filePath, + type: 'function', + lineRange: { start: 1, end: 1 }, + suggestion: `Only ${metrics.functions.covered}/${metrics.functions.total} functions are tested.`, + }); + } + + files.push({ + path: filePath, + metrics, + uncoveredLines, + uncoveredBranches, + uncoveredFunctions, + }); + } + + return { + overall, + files, + uncoveredCode, + timestamp: new Date().toISOString(), + hasReport: true, + }; + } catch (error) { + console.error('Error parsing coverage report:', error); + return createEmptyAnalysis(); + } +} + +/** + * Parse lcov.info format coverage report + */ +export function parseLcovReport(reportPath: string): CoverageAnalysis { + try { + const content = fs.readFileSync(reportPath, 'utf-8'); + const lines = content.split('\n'); + + const files: FileCoverage[] = []; + const uncoveredCode: UncoveredCode[] = []; + + let currentFile: string | null = null; + let currentMetrics = createEmptyMetrics(); + let currentUncoveredLines: number[] = []; + let currentUncoveredFunctions: string[] = []; + + let totalLines = { covered: 0, total: 0 }; + let totalFunctions = { covered: 0, total: 0 }; + let totalBranches = { covered: 0, total: 0 }; + + for (const line of lines) { + if (line.startsWith('SF:')) { + // Source file + currentFile = line.substring(3); + currentMetrics = createEmptyMetrics(); + currentUncoveredLines = []; + currentUncoveredFunctions = []; + } else if (line.startsWith('DA:')) { + // Line coverage: DA:line_number,hit_count + const [lineNum, hitCount] = line.substring(3).split(',').map(Number); + currentMetrics.lines.total++; + if (hitCount > 0) { + currentMetrics.lines.covered++; + } else { + currentUncoveredLines.push(lineNum); + } + } else if (line.startsWith('FN:')) { + // Function: FN:line_number,function_name + currentMetrics.functions.total++; + } else if (line.startsWith('FNDA:')) { + // Function hit data: FNDA:hit_count,function_name + const parts = line.substring(5).split(','); + const hitCount = parseInt(parts[0], 10); + const funcName = parts.slice(1).join(','); + if (hitCount > 0) { + currentMetrics.functions.covered++; + } else { + currentUncoveredFunctions.push(funcName); + } + } else if (line.startsWith('BRDA:')) { + // Branch: BRDA:line,block,branch,taken + const parts = line.substring(5).split(','); + currentMetrics.branches.total++; + if (parts[3] !== '-' && parseInt(parts[3], 10) > 0) { + currentMetrics.branches.covered++; + } + } else if (line === 'end_of_record' && currentFile) { + // Calculate percentages + currentMetrics.lines.pct = currentMetrics.lines.total > 0 + ? (currentMetrics.lines.covered / currentMetrics.lines.total) * 100 + : 100; + currentMetrics.functions.pct = currentMetrics.functions.total > 0 + ? (currentMetrics.functions.covered / currentMetrics.functions.total) * 100 + : 100; + currentMetrics.branches.pct = currentMetrics.branches.total > 0 + ? (currentMetrics.branches.covered / currentMetrics.branches.total) * 100 + : 100; + currentMetrics.statements = currentMetrics.lines; // Approximate + + // Accumulate totals + totalLines.covered += currentMetrics.lines.covered; + totalLines.total += currentMetrics.lines.total; + totalFunctions.covered += currentMetrics.functions.covered; + totalFunctions.total += currentMetrics.functions.total; + totalBranches.covered += currentMetrics.branches.covered; + totalBranches.total += currentMetrics.branches.total; + + // Add low coverage files to uncovered code + if (currentMetrics.lines.pct < 50 && currentUncoveredLines.length > 0) { + uncoveredCode.push({ + filePath: currentFile, + type: 'line', + lineRange: { + start: Math.min(...currentUncoveredLines), + end: Math.max(...currentUncoveredLines) + }, + suggestion: `${currentUncoveredLines.length} lines without test coverage`, + }); + } + + for (const funcName of currentUncoveredFunctions) { + uncoveredCode.push({ + filePath: currentFile, + functionName: funcName, + type: 'function', + lineRange: { start: 1, end: 1 }, + suggestion: `Function '${funcName}' has no test coverage`, + }); + } + + files.push({ + path: currentFile, + metrics: { ...currentMetrics }, + uncoveredLines: [...currentUncoveredLines], + uncoveredBranches: [], + uncoveredFunctions: [...currentUncoveredFunctions], + }); + + currentFile = null; + } + } + + // Calculate overall metrics + const overall: CoverageMetrics = { + statements: { + covered: totalLines.covered, + total: totalLines.total, + pct: totalLines.total > 0 ? (totalLines.covered / totalLines.total) * 100 : 100, + }, + branches: { + covered: totalBranches.covered, + total: totalBranches.total, + pct: totalBranches.total > 0 ? (totalBranches.covered / totalBranches.total) * 100 : 100, + }, + functions: { + covered: totalFunctions.covered, + total: totalFunctions.total, + pct: totalFunctions.total > 0 ? (totalFunctions.covered / totalFunctions.total) * 100 : 100, + }, + lines: { + covered: totalLines.covered, + total: totalLines.total, + pct: totalLines.total > 0 ? (totalLines.covered / totalLines.total) * 100 : 100, + }, + }; + + return { + overall, + files, + uncoveredCode, + timestamp: new Date().toISOString(), + hasReport: true, + }; + } catch (error) { + console.error('Error parsing LCOV report:', error); + return createEmptyAnalysis(); + } +} + +// ========== ESLint Static Analysis ========== + +/** + * Run ESLint on specified files or directory + */ +export async function runEslintAnalysis( + targetPath: string, + options: { fix?: boolean; format?: 'json' | 'stylish' } = {} +): Promise { + try { + const eslintPath = path.join(targetPath, 'node_modules', '.bin', 'eslint'); + const hasEslint = fs.existsSync(eslintPath); + + if (!hasEslint) { + console.log('ESLint not found in project, skipping static analysis'); + return createEmptyStaticAnalysis(); + } + + const cmd = `${eslintPath} . --format json --ext .js,.jsx,.ts,.tsx 2>/dev/null || true`; + + const { stdout } = await execAsync(cmd, { + cwd: targetPath, + maxBuffer: 10 * 1024 * 1024, // 10MB buffer + }); + + if (!stdout.trim()) { + return createEmptyStaticAnalysis(); + } + + const results = JSON.parse(stdout) as Array<{ + filePath: string; + messages: Array<{ + line: number; + column: number; + severity: 1 | 2; + ruleId: string; + message: string; + fix?: { range: [number, number]; text: string }; + }>; + errorCount: number; + warningCount: number; + fixableErrorCount: number; + fixableWarningCount: number; + }>; + + const issues: StaticAnalysisIssue[] = []; + let errors = 0; + let warnings = 0; + let info = 0; + let fixable = 0; + + for (const file of results) { + for (const msg of file.messages) { + const severity = msg.severity === 2 ? 'error' : 'warning'; + issues.push({ + filePath: file.filePath, + line: msg.line, + column: msg.column, + severity, + ruleId: msg.ruleId || 'unknown', + message: msg.message, + suggestion: msg.fix ? 'Auto-fixable' : undefined, + }); + + if (severity === 'error') errors++; + else warnings++; + if (msg.fix) fixable++; + } + } + + return { + issues, + summary: { errors, warnings, info, fixable }, + hasResults: issues.length > 0, + }; + } catch (error) { + console.error('Error running ESLint:', error); + return createEmptyStaticAnalysis(); + } +} + +// ========== Combined Analysis ========== + +/** + * Get full coverage analysis from existing reports + */ +export function getCoverageAnalysis(repoPath: string = '.'): CoverageAnalysis { + const report = detectCoverageReport(repoPath); + + if (!report.found || !report.path) { + return createEmptyAnalysis(); + } + + switch (report.format) { + case 'json': + return parseCoverageJson(report.path); + case 'lcov': + return parseLcovReport(report.path); + default: + return createEmptyAnalysis(); + } +} + +/** + * Run coverage analysis using nyc (generates report if needed) + */ +export async function runCoverageAnalysis( + repoPath: string = '.', + options: { regenerate?: boolean } = {} +): Promise { + // Check for existing report first + if (!options.regenerate) { + const existing = getCoverageAnalysis(repoPath); + if (existing.hasReport) { + return existing; + } + } + + // Try to run coverage + try { + console.log('📊 Running coverage analysis...'); + + // Check if nyc or jest --coverage is available + const packageJsonPath = path.join(repoPath, 'package.json'); + if (!fs.existsSync(packageJsonPath)) { + return createEmptyAnalysis(); + } + + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); + const scripts = packageJson.scripts || {}; + + let cmd: string | null = null; + + if (scripts['test:coverage']) { + cmd = 'npm run test:coverage'; + } else if (scripts['coverage']) { + cmd = 'npm run coverage'; + } else if (scripts['test'] && packageJson.devDependencies?.jest) { + cmd = 'npm test -- --coverage --coverageReporters=json-summary'; + } else if (packageJson.devDependencies?.nyc) { + cmd = 'npx nyc --reporter=json-summary npm test'; + } + + if (cmd) { + console.log(` Running: ${cmd}`); + await execAsync(cmd, { cwd: repoPath, timeout: 300000 }); // 5 min timeout + return getCoverageAnalysis(repoPath); + } + + return createEmptyAnalysis(); + } catch (error) { + console.error('Coverage analysis failed:', error); + return createEmptyAnalysis(); + } +} + +/** + * Get files with low coverage that need test suggestions + */ +export function getLowCoverageFiles( + analysis: CoverageAnalysis, + threshold: number = 50 +): FileCoverage[] { + return analysis.files.filter(f => f.metrics.lines.pct < threshold); +} + +/** + * Format coverage analysis for CLI output + */ +export function formatCoverageReport(analysis: CoverageAnalysis): string { + if (!analysis.hasReport) { + return '📊 No coverage report found. Run tests with coverage to generate one.'; + } + + const lines: string[] = []; + + lines.push('📊 Coverage Summary'); + lines.push('═'.repeat(50)); + lines.push(` Statements: ${analysis.overall.statements.pct.toFixed(1)}% (${analysis.overall.statements.covered}/${analysis.overall.statements.total})`); + lines.push(` Branches: ${analysis.overall.branches.pct.toFixed(1)}% (${analysis.overall.branches.covered}/${analysis.overall.branches.total})`); + lines.push(` Functions: ${analysis.overall.functions.pct.toFixed(1)}% (${analysis.overall.functions.covered}/${analysis.overall.functions.total})`); + lines.push(` Lines: ${analysis.overall.lines.pct.toFixed(1)}% (${analysis.overall.lines.covered}/${analysis.overall.lines.total})`); + + const lowCoverage = getLowCoverageFiles(analysis, 50); + if (lowCoverage.length > 0) { + lines.push(''); + lines.push('⚠️ Files with low coverage (<50%):'); + for (const file of lowCoverage.slice(0, 10)) { + const shortPath = file.path.split('/').slice(-2).join('/'); + lines.push(` ${shortPath}: ${file.metrics.lines.pct.toFixed(1)}%`); + } + if (lowCoverage.length > 10) { + lines.push(` ... and ${lowCoverage.length - 10} more files`); + } + } + + if (analysis.uncoveredCode.length > 0) { + lines.push(''); + lines.push('🔍 Uncovered code suggestions:'); + for (const item of analysis.uncoveredCode.slice(0, 5)) { + lines.push(` ${item.suggestion || 'Needs test coverage'}`); + } + } + + return lines.join('\n'); +} + +/** + * Format static analysis for CLI output + */ +export function formatStaticAnalysis(analysis: StaticAnalysis): string { + if (!analysis.hasResults) { + return '✅ No static analysis issues found.'; + } + + const lines: string[] = []; + + lines.push('🔬 Static Analysis Summary'); + lines.push('═'.repeat(50)); + lines.push(` Errors: ${analysis.summary.errors}`); + lines.push(` Warnings: ${analysis.summary.warnings}`); + lines.push(` Fixable: ${analysis.summary.fixable}`); + + if (analysis.issues.length > 0) { + lines.push(''); + lines.push('Top issues:'); + for (const issue of analysis.issues.slice(0, 5)) { + const shortPath = issue.filePath.split('/').slice(-2).join('/'); + const icon = issue.severity === 'error' ? '❌' : '⚠️'; + lines.push(` ${icon} ${shortPath}:${issue.line} - ${issue.message}`); + } + } + + return lines.join('\n'); +} + +// ========== Helper Functions ========== + +function createEmptyMetrics(): CoverageMetrics { + return { + statements: { covered: 0, total: 0, pct: 0 }, + branches: { covered: 0, total: 0, pct: 0 }, + functions: { covered: 0, total: 0, pct: 0 }, + lines: { covered: 0, total: 0, pct: 0 }, + }; +} + +function createEmptyAnalysis(): CoverageAnalysis { + return { + overall: createEmptyMetrics(), + files: [], + uncoveredCode: [], + timestamp: new Date().toISOString(), + hasReport: false, + }; +} + +function createEmptyStaticAnalysis(): StaticAnalysis { + return { + issues: [], + summary: { errors: 0, warnings: 0, info: 0, fixable: 0 }, + hasResults: false, + }; +} diff --git a/src/tools/coverage-reporter.ts b/src/tools/coverage-reporter.ts new file mode 100644 index 0000000..fbded56 --- /dev/null +++ b/src/tools/coverage-reporter.ts @@ -0,0 +1,341 @@ +/** + * Coverage Reporter Tool for PR Analysis + * Reads coverage reports and extracts metrics when coverage tool is configured + */ + +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +import fs from 'node:fs'; +import path from 'node:path'; +import { CoverageReport } from '../types/agent.types.js'; + +// Common coverage file locations +const COVERAGE_PATHS = { + jest: ['coverage/coverage-summary.json', 'coverage/lcov.info', 'coverage/coverage-final.json'], + nyc: ['coverage/coverage-summary.json', '.nyc_output/coverage.json', 'coverage/lcov.info'], + vitest: ['coverage/coverage-summary.json', 'coverage/lcov.info'], + pytest: ['coverage.xml', 'htmlcov/coverage.json', '.coverage'], + generic: ['coverage.json', 'coverage/lcov.info', 'coverage.xml'], +}; + +/** + * Detect if coverage tool is configured in the project + */ +export function detectCoverageTool(repoPath: string = '.'): { + tool: string | null; + configured: boolean; + coveragePath?: string; +} { + const packageJsonPath = path.join(repoPath, 'package.json'); + + // Check for Node.js project with coverage config + if (fs.existsSync(packageJsonPath)) { + try { + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); + + // Check Jest config + if (packageJson.jest?.collectCoverage || packageJson.jest?.coverageDirectory) { + return { tool: 'jest', configured: true }; + } + + // Check for coverage scripts + const scripts = packageJson.scripts || {}; + const hasCoverageScript = Object.values(scripts).some((script: unknown) => + typeof script === 'string' && (script.includes('--coverage') || script.includes('nyc')) + ); + + if (hasCoverageScript) { + // Determine which tool + const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }; + if (deps.jest) return { tool: 'jest', configured: true }; + if (deps.nyc || deps['istanbul']) return { tool: 'nyc', configured: true }; + if (deps.vitest) return { tool: 'vitest', configured: true }; + if (deps.c8) return { tool: 'c8', configured: true }; + return { tool: 'node', configured: true }; + } + } catch (e) { + // Ignore parse errors + } + } + + // Check for Jest config file + if (fs.existsSync(path.join(repoPath, 'jest.config.js')) || fs.existsSync(path.join(repoPath, 'jest.config.ts'))) { + try { + const configPath = fs.existsSync(path.join(repoPath, 'jest.config.js')) + ? path.join(repoPath, 'jest.config.js') + : path.join(repoPath, 'jest.config.ts'); + const content = fs.readFileSync(configPath, 'utf-8'); + if (content.includes('collectCoverage') || content.includes('coverageDirectory')) { + return { tool: 'jest', configured: true }; + } + } catch (e) { + // Ignore read errors + } + } + + // Check for Python coverage + const setupCfg = path.join(repoPath, 'setup.cfg'); + const pyprojectToml = path.join(repoPath, 'pyproject.toml'); + + if (fs.existsSync(setupCfg)) { + try { + const content = fs.readFileSync(setupCfg, 'utf-8'); + if (content.includes('[coverage:') || content.includes('coverage')) { + return { tool: 'pytest-cov', configured: true }; + } + } catch (e) { + // Ignore read errors + } + } + + if (fs.existsSync(pyprojectToml)) { + try { + const content = fs.readFileSync(pyprojectToml, 'utf-8'); + if (content.includes('[tool.coverage]') || content.includes('pytest-cov')) { + return { tool: 'pytest-cov', configured: true }; + } + } catch (e) { + // Ignore read errors + } + } + + return { tool: null, configured: false }; +} + +/** + * Find existing coverage report files + */ +export function findCoverageFiles(repoPath: string = '.'): string[] { + const foundFiles: string[] = []; + + for (const paths of Object.values(COVERAGE_PATHS)) { + for (const coveragePath of paths) { + const fullPath = path.join(repoPath, coveragePath); + if (fs.existsSync(fullPath)) { + foundFiles.push(fullPath); + } + } + } + + return [...new Set(foundFiles)]; // Remove duplicates +} + +/** + * Parse Jest/NYC coverage-summary.json format + */ +function parseJestCoverageSummary(filePath: string): CoverageReport | null { + try { + const content = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + const total = content.total; + + if (!total) return null; + + const fileBreakdown: CoverageReport['fileBreakdown'] = []; + + for (const [file, data] of Object.entries(content)) { + if (file === 'total') continue; + const fileData = data as { lines?: { pct: number }; branches?: { pct: number } }; + fileBreakdown.push({ + file, + lineCoverage: fileData.lines?.pct || 0, + branchCoverage: fileData.branches?.pct, + }); + } + + return { + available: true, + overallPercentage: total.lines?.pct || total.statements?.pct || 0, + lineCoverage: total.lines?.pct, + branchCoverage: total.branches?.pct, + fileBreakdown: fileBreakdown.slice(0, 20), // Limit to 20 files + coverageTool: 'jest/nyc', + }; + } catch (e) { + return null; + } +} + +/** + * Parse LCOV format + */ +function parseLcov(filePath: string): CoverageReport | null { + try { + const content = fs.readFileSync(filePath, 'utf-8'); + const files: Array<{ file: string; linesHit: number; linesTotal: number }> = []; + let currentFile = ''; + let linesHit = 0; + let linesTotal = 0; + + for (const line of content.split('\n')) { + if (line.startsWith('SF:')) { + currentFile = line.substring(3); + linesHit = 0; + linesTotal = 0; + } else if (line.startsWith('LH:')) { + linesHit = parseInt(line.substring(3), 10); + } else if (line.startsWith('LF:')) { + linesTotal = parseInt(line.substring(3), 10); + } else if (line === 'end_of_record' && currentFile) { + files.push({ file: currentFile, linesHit, linesTotal }); + currentFile = ''; + } + } + + const totalHit = files.reduce((sum, f) => sum + f.linesHit, 0); + const totalLines = files.reduce((sum, f) => sum + f.linesTotal, 0); + const overallPercentage = totalLines > 0 ? (totalHit / totalLines) * 100 : 0; + + return { + available: true, + overallPercentage: Math.round(overallPercentage * 100) / 100, + lineCoverage: overallPercentage, + fileBreakdown: files.slice(0, 20).map(f => ({ + file: f.file, + lineCoverage: f.linesTotal > 0 ? (f.linesHit / f.linesTotal) * 100 : 0, + })), + coverageTool: 'lcov', + }; + } catch (e) { + return null; + } +} + +/** + * Parse Cobertura XML format + */ +function parseCobertura(filePath: string): CoverageReport | null { + try { + const content = fs.readFileSync(filePath, 'utf-8'); + + // Simple regex parsing for line-rate attribute + const lineRateMatch = content.match(/line-rate="([0-9.]+)"/); + const branchRateMatch = content.match(/branch-rate="([0-9.]+)"/); + + if (!lineRateMatch) return null; + + const lineRate = parseFloat(lineRateMatch[1]) * 100; + const branchRate = branchRateMatch ? parseFloat(branchRateMatch[1]) * 100 : undefined; + + return { + available: true, + overallPercentage: Math.round(lineRate * 100) / 100, + lineCoverage: lineRate, + branchCoverage: branchRate, + coverageTool: 'cobertura', + }; + } catch (e) { + return null; + } +} + +/** + * Read and parse coverage report + */ +export function readCoverageReport(repoPath: string = '.'): CoverageReport { + const coverageFiles = findCoverageFiles(repoPath); + + if (coverageFiles.length === 0) { + return { available: false }; + } + + // Try to parse each file type + for (const filePath of coverageFiles) { + const fileName = path.basename(filePath); + + if (fileName === 'coverage-summary.json' || fileName === 'coverage.json') { + const report = parseJestCoverageSummary(filePath); + if (report) return report; + } + + if (fileName === 'lcov.info' || fileName.endsWith('.lcov')) { + const report = parseLcov(filePath); + if (report) return report; + } + + if (fileName === 'coverage.xml' || fileName.endsWith('cobertura.xml')) { + const report = parseCobertura(filePath); + if (report) return report; + } + } + + return { available: false }; +} + +/** + * Create coverage reporter tool + */ +export function createCoverageReporterTool() { + return new DynamicStructuredTool({ + name: 'report_coverage', + description: 'Read test coverage reports and extract metrics (only if coverage tool is configured)', + schema: z.object({ + repoPath: z.string().optional().describe('Repository path to check for coverage'), + forceRead: z.boolean().optional().describe('Force reading coverage even if not configured'), + }), + func: async ({ repoPath, forceRead }: { repoPath?: string; forceRead?: boolean }) => { + const projectPath = repoPath || '.'; + + // Check if coverage tool is configured + const toolConfig = detectCoverageTool(projectPath); + + if (!toolConfig.configured && !forceRead) { + return JSON.stringify({ + available: false, + reason: 'No coverage tool configured in project', + configured: false, + }); + } + + // Try to read coverage report + const report = readCoverageReport(projectPath); + + return JSON.stringify({ + ...report, + configured: toolConfig.configured, + tool: toolConfig.tool, + }); + }, + }); +} + +/** + * Format coverage report for display + */ +export function formatCoverageReport(report: CoverageReport): string { + if (!report.available) { + return 'No coverage data available'; + } + + let output = ''; + + if (report.overallPercentage !== undefined) { + const emoji = report.overallPercentage >= 80 ? '🟢' : report.overallPercentage >= 60 ? '🟡' : '🔴'; + output += `${emoji} Overall Coverage: ${report.overallPercentage.toFixed(1)}%\n`; + } + + if (report.lineCoverage !== undefined) { + output += ` Lines: ${report.lineCoverage.toFixed(1)}%\n`; + } + + if (report.branchCoverage !== undefined) { + output += ` Branches: ${report.branchCoverage.toFixed(1)}%\n`; + } + + if (report.delta !== undefined) { + const deltaEmoji = report.delta >= 0 ? '📈' : '📉'; + output += `${deltaEmoji} Coverage Delta: ${report.delta >= 0 ? '+' : ''}${report.delta.toFixed(1)}%\n`; + } + + if (report.fileBreakdown && report.fileBreakdown.length > 0) { + output += '\nFile Breakdown:\n'; + for (const file of report.fileBreakdown.slice(0, 10)) { + const emoji = file.lineCoverage >= 80 ? '✅' : file.lineCoverage >= 60 ? '⚠️' : '❌'; + output += ` ${emoji} ${path.basename(file.file)}: ${file.lineCoverage.toFixed(1)}%\n`; + } + if (report.fileBreakdown.length > 10) { + output += ` ... and ${report.fileBreakdown.length - 10} more files\n`; + } + } + + return output; +} diff --git a/src/tools/devops-cost-estimator.ts b/src/tools/devops-cost-estimator.ts new file mode 100644 index 0000000..4493635 --- /dev/null +++ b/src/tools/devops-cost-estimator.ts @@ -0,0 +1,387 @@ +/** + * DevOps Cost Estimator Tool for PR Analysis + * Estimates AWS infrastructure costs for DevOps-related changes (IaC, Dockerfiles, etc.) + * Uses MCP to connect to AWS for cost estimation when available + */ + +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +import fs from 'node:fs'; +import path from 'node:path'; +import { DevOpsCostEstimate } from '../types/agent.types.js'; + +// DevOps file patterns +const DEVOPS_PATTERNS = { + terraform: [/\.tf$/, /\.tfvars$/], + cloudformation: [/template\.(yaml|yml|json)$/, /cloudformation\.(yaml|yml|json)$/], + cdk: [/cdk\.json$/, /\.ts$.*cdk/], + pulumi: [/Pulumi\.(yaml|yml)$/, /pulumi\..*\.(ts|js|py|go)$/], + docker: [/Dockerfile/, /docker-compose\.(yaml|yml)$/], + kubernetes: [/k8s.*\.(yaml|yml)$/, /kubernetes.*\.(yaml|yml)$/, /\.kube.*\.(yaml|yml)$/], + github_actions: [/\.github\/workflows\/.*\.(yaml|yml)$/], + serverless: [/serverless\.(yaml|yml|json)$/], +}; + +// AWS resource cost estimates (monthly USD, approximate) +const AWS_RESOURCE_COSTS: Record = { + 'ec2-t3.micro': { min: 8, typical: 8.5, max: 10 }, + 'ec2-t3.small': { min: 15, typical: 17, max: 20 }, + 'ec2-t3.medium': { min: 30, typical: 34, max: 40 }, + 'ec2-t3.large': { min: 60, typical: 68, max: 80 }, + 'ec2-m5.large': { min: 70, typical: 80, max: 95 }, + 'ec2-m5.xlarge': { min: 140, typical: 160, max: 190 }, + 'lambda-1m-invocations': { min: 0.2, typical: 0.4, max: 2 }, + 'lambda-10m-invocations': { min: 2, typical: 4, max: 20 }, + 's3-storage-gb': { min: 0.023, typical: 0.023, max: 0.025 }, + 's3-requests-1k': { min: 0.004, typical: 0.005, max: 0.006 }, + 'rds-db.t3.micro': { min: 13, typical: 15, max: 18 }, + 'rds-db.t3.small': { min: 26, typical: 30, max: 35 }, + 'rds-db.t3.medium': { min: 52, typical: 60, max: 70 }, + 'rds-db.m5.large': { min: 140, typical: 160, max: 190 }, + 'ecs-task-256cpu-512mem': { min: 10, typical: 12, max: 15 }, + 'ecs-task-512cpu-1024mem': { min: 20, typical: 24, max: 30 }, + 'ecs-task-1024cpu-2048mem': { min: 40, typical: 48, max: 60 }, + 'alb': { min: 16, typical: 22, max: 30 }, + 'nat-gateway': { min: 32, typical: 45, max: 60 }, + 'elasticache-t3.micro': { min: 12, typical: 15, max: 18 }, + 'cloudfront-1tb': { min: 85, typical: 100, max: 120 }, + 'api-gateway-1m-requests': { min: 3.5, typical: 4, max: 5 }, + 'sqs-1m-requests': { min: 0.4, typical: 0.5, max: 0.6 }, + 'sns-1m-notifications': { min: 0.5, typical: 0.6, max: 0.7 }, + 'dynamodb-25wcu-25rcu': { min: 25, typical: 30, max: 40 }, +}; + +/** + * Check if a file is a DevOps-related file + */ +export function isDevOpsFile(filePath: string): { isDevOps: boolean; type: string | null } { + for (const [type, patterns] of Object.entries(DEVOPS_PATTERNS)) { + for (const pattern of patterns) { + if (pattern.test(filePath)) { + return { isDevOps: true, type }; + } + } + } + return { isDevOps: false, type: null }; +} + +/** + * Extract AWS resources from Terraform content + */ +function extractTerraformResources(content: string): Array<{ resource: string; type: string }> { + const resources: Array<{ resource: string; type: string }> = []; + + // Match resource blocks - handles both regular files and diff format (with + prefix) + const resourceRegex = /^[\+\s]*resource\s+"([^"]+)"\s+"([^"]+)"/gm; + let match; + + console.error(`[DevOps] Extracting Terraform resources from content length: ${content.length}`); + console.error(`[DevOps] First 200 chars: ${content.substring(0, 200)}`); + + while ((match = resourceRegex.exec(content)) !== null) { + const resourceType = match[1]; + const resourceName = match[2]; + console.error(`[DevOps] Found resource: ${resourceType} "${resourceName}"`); + + // Map Terraform resources to our cost categories + if (resourceType.startsWith('aws_instance')) { + resources.push({ resource: resourceName, type: 'ec2' }); + } else if (resourceType.startsWith('aws_lambda')) { + resources.push({ resource: resourceName, type: 'lambda' }); + } else if (resourceType.startsWith('aws_s3')) { + resources.push({ resource: resourceName, type: 's3' }); + } else if (resourceType.startsWith('aws_rds') || resourceType.startsWith('aws_db')) { + resources.push({ resource: resourceName, type: 'rds' }); + } else if (resourceType.startsWith('aws_ecs')) { + resources.push({ resource: resourceName, type: 'ecs' }); + } else if (resourceType.startsWith('aws_alb') || resourceType.startsWith('aws_lb')) { + resources.push({ resource: resourceName, type: 'alb' }); + } else if (resourceType.startsWith('aws_nat')) { + resources.push({ resource: resourceName, type: 'nat-gateway' }); + } else if (resourceType.startsWith('aws_elasticache')) { + resources.push({ resource: resourceName, type: 'elasticache' }); + } else if (resourceType.startsWith('aws_cloudfront')) { + resources.push({ resource: resourceName, type: 'cloudfront' }); + } else if (resourceType.startsWith('aws_api_gateway') || resourceType.startsWith('aws_apigatewayv2')) { + resources.push({ resource: resourceName, type: 'api-gateway' }); + } else if (resourceType.startsWith('aws_sqs')) { + resources.push({ resource: resourceName, type: 'sqs' }); + } else if (resourceType.startsWith('aws_sns')) { + resources.push({ resource: resourceName, type: 'sns' }); + } else if (resourceType.startsWith('aws_dynamodb')) { + resources.push({ resource: resourceName, type: 'dynamodb' }); + } + } + + console.error(`[DevOps] Extracted ${resources.length} Terraform resources`); + return resources; +} + +/** + * Extract AWS resources from CloudFormation content + */ +function extractCloudFormationResources(content: string): Array<{ resource: string; type: string }> { + const resources: Array<{ resource: string; type: string }> = []; + + // Simple pattern matching for CFN resources + const typeMap: Record = { + 'AWS::EC2::Instance': 'ec2', + 'AWS::Lambda::Function': 'lambda', + 'AWS::S3::Bucket': 's3', + 'AWS::RDS::DBInstance': 'rds', + 'AWS::ECS::Service': 'ecs', + 'AWS::ECS::TaskDefinition': 'ecs', + 'AWS::ElasticLoadBalancingV2::LoadBalancer': 'alb', + 'AWS::EC2::NatGateway': 'nat-gateway', + 'AWS::ElastiCache::CacheCluster': 'elasticache', + 'AWS::CloudFront::Distribution': 'cloudfront', + 'AWS::ApiGateway::RestApi': 'api-gateway', + 'AWS::ApiGatewayV2::Api': 'api-gateway', + 'AWS::SQS::Queue': 'sqs', + 'AWS::SNS::Topic': 'sns', + 'AWS::DynamoDB::Table': 'dynamodb', + }; + + for (const [awsType, costType] of Object.entries(typeMap)) { + if (content.includes(awsType)) { + // Try to extract logical ID + const regex = new RegExp(`(\\w+):\\s*\\n\\s*Type:\\s*['"]?${awsType.replace(/::/g, '::')}`, 'g'); + const matches = content.matchAll(regex); + for (const match of matches) { + resources.push({ resource: match[1] || costType, type: costType }); + } + // Fallback if no match found but type exists + if (resources.filter(r => r.type === costType).length === 0) { + resources.push({ resource: costType, type: costType }); + } + } + } + + return resources; +} + +/** + * Estimate cost for a resource type + */ +function estimateResourceCost(resourceType: string): DevOpsCostEstimate { + // Find matching cost entry + let costKey = ''; + let confidence: 'high' | 'medium' | 'low' = 'low'; + + switch (resourceType) { + case 'ec2': + costKey = 'ec2-t3.medium'; + confidence = 'medium'; + break; + case 'lambda': + costKey = 'lambda-1m-invocations'; + confidence = 'low'; + break; + case 's3': + costKey = 's3-storage-gb'; + confidence = 'low'; + break; + case 'rds': + costKey = 'rds-db.t3.small'; + confidence = 'medium'; + break; + case 'ecs': + costKey = 'ecs-task-512cpu-1024mem'; + confidence = 'medium'; + break; + case 'alb': + costKey = 'alb'; + confidence = 'high'; + break; + case 'nat-gateway': + costKey = 'nat-gateway'; + confidence = 'high'; + break; + case 'elasticache': + costKey = 'elasticache-t3.micro'; + confidence = 'medium'; + break; + case 'cloudfront': + costKey = 'cloudfront-1tb'; + confidence = 'low'; + break; + case 'api-gateway': + costKey = 'api-gateway-1m-requests'; + confidence = 'low'; + break; + case 'sqs': + costKey = 'sqs-1m-requests'; + confidence = 'low'; + break; + case 'sns': + costKey = 'sns-1m-notifications'; + confidence = 'low'; + break; + case 'dynamodb': + costKey = 'dynamodb-25wcu-25rcu'; + confidence = 'low'; + break; + default: + return { + resource: resourceType, + resourceType, + estimatedNewCost: 0, + confidence: 'low', + details: 'Unknown resource type - manual estimation required', + }; + } + + const cost = AWS_RESOURCE_COSTS[costKey]; + if (!cost) { + return { + resource: resourceType, + resourceType, + estimatedNewCost: 0, + confidence: 'low', + details: 'Cost data not available', + }; + } + + return { + resource: resourceType, + resourceType, + estimatedNewCost: cost.typical, + confidence, + details: `Estimated $${cost.min.toFixed(2)} - $${cost.max.toFixed(2)}/month`, + }; +} + +/** + * Analyze DevOps files and estimate costs + */ +export function analyzeDevOpsFiles(files: Array<{ path: string; diff: string }>): { + hasDevOpsChanges: boolean; + fileTypes: string[]; + estimates: DevOpsCostEstimate[]; + totalEstimatedCost: number; +} { + console.error(`[DevOps] Analyzing ${files.length} files`); + const devOpsFiles = files.filter(f => isDevOpsFile(f.path).isDevOps); + + console.error(`[DevOps] Found ${devOpsFiles.length} DevOps files:`, devOpsFiles.map(f => f.path)); + + if (devOpsFiles.length === 0) { + return { + hasDevOpsChanges: false, + fileTypes: [], + estimates: [], + totalEstimatedCost: 0, + }; + } + + const fileTypes = new Set(); + const allResources: Array<{ resource: string; type: string }> = []; + + for (const file of devOpsFiles) { + const { type } = isDevOpsFile(file.path); + if (type) fileTypes.add(type); + + console.error(`[DevOps] Processing file: ${file.path} (type: ${type})`); + + // Get the full content (in real scenario, we'd read the file) + // For now, analyze the diff + const content = file.diff; + + if (type === 'terraform') { + allResources.push(...extractTerraformResources(content)); + } else if (type === 'cloudformation') { + allResources.push(...extractCloudFormationResources(content)); + } + // Add more extractors for other IaC types as needed + } + + // Estimate costs for each resource + const estimates: DevOpsCostEstimate[] = []; + const seenTypes = new Set(); + + console.error(`[DevOps] Total resources found: ${allResources.length}`); + + for (const resource of allResources) { + if (!seenTypes.has(resource.type)) { + seenTypes.add(resource.type); + const estimate = estimateResourceCost(resource.type); + console.error(`[DevOps] Estimated cost for ${resource.type}: $${estimate.estimatedNewCost}/month`); + estimates.push(estimate); + } + } + + const totalEstimatedCost = estimates.reduce((sum, e) => sum + e.estimatedNewCost, 0); + + console.error(`[DevOps] Final: ${estimates.length} estimates, total: $${totalEstimatedCost}/month`); + + return { + hasDevOpsChanges: true, + fileTypes: Array.from(fileTypes), + estimates, + totalEstimatedCost, + }; +} + +/** + * Create DevOps cost estimator tool + */ +export function createDevOpsCostEstimatorTool() { + return new DynamicStructuredTool({ + name: 'estimate_devops_costs', + description: 'Analyze DevOps/IaC files and estimate AWS infrastructure costs', + schema: z.object({ + files: z.array(z.object({ + path: z.string(), + diff: z.string(), + })).describe('Array of changed files to analyze'), + awsCredentials: z.object({ + accessKeyId: z.string().optional(), + secretAccessKey: z.string().optional(), + region: z.string().optional(), + }).optional().describe('AWS credentials for live cost lookup (optional)'), + }), + func: async ({ files }: { files: Array<{ path: string; diff: string }>; awsCredentials?: { accessKeyId?: string; secretAccessKey?: string; region?: string } }) => { + const analysis = analyzeDevOpsFiles(files); + + if (!analysis.hasDevOpsChanges) { + return JSON.stringify({ + hasDevOpsChanges: false, + message: 'No DevOps/IaC files detected in changes', + }); + } + + return JSON.stringify({ + hasDevOpsChanges: true, + fileTypes: analysis.fileTypes, + estimates: analysis.estimates, + totalEstimatedCost: analysis.totalEstimatedCost, + message: `Detected ${analysis.fileTypes.join(', ')} changes. Estimated monthly cost impact: $${analysis.totalEstimatedCost.toFixed(2)}`, + disclaimer: 'Cost estimates are approximate and based on typical resource sizes. Actual costs depend on usage patterns, region, and specific configurations.', + }); + }, + }); +} + +/** + * Format cost estimates for display + */ +export function formatCostEstimates(estimates: DevOpsCostEstimate[], totalCost: number): string { + if (estimates.length === 0) { + return 'No cost estimates available'; + } + + let output = '💰 AWS Cost Estimates\n\n'; + + for (const estimate of estimates) { + const emoji = estimate.confidence === 'high' ? '🟢' : estimate.confidence === 'medium' ? '🟡' : '🔴'; + output += `${emoji} ${estimate.resourceType.toUpperCase()}: ~$${estimate.estimatedNewCost.toFixed(2)}/month\n`; + if (estimate.details) { + output += ` ${estimate.details}\n`; + } + } + + output += `\n📊 Total Estimated Impact: ~$${totalCost.toFixed(2)}/month\n`; + output += '\n⚠️ Estimates are approximate. Actual costs depend on usage and configuration.\n'; + + return output; +} diff --git a/src/tools/index.ts b/src/tools/index.ts index 139aeb8..4f5a873 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -11,3 +11,55 @@ export { createCodeSuggestionTool, } from './pr-analysis-tools.js'; +export { + detectTestFramework, + isTestFile, + isCodeFile, + suggestTestFilePath, + createTestSuggestionTool, + generateTestTemplate, + analyzeTestQuality, + formatTestEnhancement, +} from './test-suggestion-tool.js'; +export type { TestEnhancement } from './test-suggestion-tool.js'; + +export { + detectCoverageTool, + findCoverageFiles, + readCoverageReport, + createCoverageReporterTool, + formatCoverageReport, +} from './coverage-reporter.js'; + +export { + isDevOpsFile, + analyzeDevOpsFiles, + createDevOpsCostEstimatorTool, + formatCostEstimates, +} from './devops-cost-estimator.js'; + +export { + classifyProject, + createProjectClassifierTool, + formatClassification, +} from './project-classifier.js'; + +export { + getCoverageAnalysis, + runCoverageAnalysis, + runEslintAnalysis, + getLowCoverageFiles, + detectCoverageReport, + parseCoverageJson, + parseLcovReport, + formatCoverageReport as formatCoverageAnalysis, + formatStaticAnalysis, +} from './coverage-analyzer.js'; +export type { + CoverageMetrics, + FileCoverage, + UncoveredCode, + CoverageAnalysis, + StaticAnalysisIssue, + StaticAnalysis, +} from './coverage-analyzer.js'; diff --git a/src/tools/project-classifier.ts b/src/tools/project-classifier.ts new file mode 100644 index 0000000..8163f4c --- /dev/null +++ b/src/tools/project-classifier.ts @@ -0,0 +1,336 @@ +/** + * Project Classifier Tool + * + * Distinguishes between business logic and QA projects based on file patterns, + * content analysis, and project structure. This helps tailor analysis and + * recommendations to the project type. + * + * Business Logic Projects: + * - Focus on feature implementation, data models, APIs, business rules + * - Should prioritize: architecture review, performance, security + * + * QA/Test Projects: + * - Focus on testing, automation, test frameworks + * - Should prioritize: test coverage, test quality, maintainability + */ + +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; + +export interface ProjectClassification { + projectType: 'business_logic' | 'qa_testing' | 'mixed' | 'unknown'; + confidence: number; // 0-1 + signals: { + businessLogicSignals: string[]; + qaTestingSignals: string[]; + }; + recommendations: string[]; +} + +/** + * Patterns that indicate business logic code + */ +const BUSINESS_LOGIC_PATTERNS = { + // File patterns + filePatterns: [ + /src\/.*\/(models?|entities|domain)\//i, + /src\/.*\/(services?|business|logic)\//i, + /src\/.*\/(controllers?|handlers?|routes?)\//i, + /src\/.*\/(api|graphql|rest)\//i, + /src\/.*\/(repositories?|dao|database)\//i, + /src\/.*\/(utils?|helpers?|lib)\//i, + /src\/.*\/(components?|views?|pages?)\//i, + ], + // Content patterns (in code) + contentKeywords: [ + 'class ', 'interface ', 'type ', 'enum ', + 'async ', 'await ', 'Promise', + 'export ', 'import ', + 'function', 'const', 'let', + 'router.', 'app.', 'express', + 'schema', 'model', 'entity', + 'query', 'mutation', 'resolver', + 'middleware', 'validation', + 'authentication', 'authorization', + ], +}; + +/** + * Patterns that indicate QA/testing code + */ +const QA_TESTING_PATTERNS = { + // File patterns + filePatterns: [ + /test\//i, + /__tests__\//i, + /spec\//i, + /e2e\//i, + /integration\//i, + /\.test\./i, + /\.spec\./i, + /\.e2e\./i, + /cypress\//i, + /playwright\//i, + /selenium\//i, + ], + // Content patterns + contentKeywords: [ + 'describe(', 'it(', 'test(', + 'expect(', 'assert', 'should', + 'beforeEach', 'afterEach', 'beforeAll', 'afterAll', + 'jest.', 'vitest.', 'mocha', + 'cy.', 'page.', 'browser.', + 'fixture', 'mock', 'stub', 'spy', + 'snapshot', 'toMatchSnapshot', + 'toHaveBeenCalled', 'toEqual', 'toBe', + ], +}; + +/** + * Classify a project based on changed files + */ +export function classifyProject( + changedFiles: Array<{ filename: string; patch?: string }> +): ProjectClassification { + let businessLogicScore = 0; + let qaTestingScore = 0; + const businessLogicSignals: string[] = []; + const qaTestingSignals: string[] = []; + + for (const file of changedFiles) { + const { filename, patch } = file; + + // Check file patterns for business logic + for (const pattern of BUSINESS_LOGIC_PATTERNS.filePatterns) { + if (pattern.test(filename)) { + businessLogicScore += 1; + businessLogicSignals.push(`Business logic file: ${filename}`); + break; + } + } + + // Check file patterns for QA/testing + for (const pattern of QA_TESTING_PATTERNS.filePatterns) { + if (pattern.test(filename)) { + qaTestingScore += 1; + qaTestingSignals.push(`Test file: ${filename}`); + break; + } + } + + // Analyze patch content if available + if (patch) { + // Count business logic keywords + const businessKeywordCount = BUSINESS_LOGIC_PATTERNS.contentKeywords.filter( + keyword => patch.includes(keyword) + ).length; + + // Count QA/testing keywords + const qaKeywordCount = QA_TESTING_PATTERNS.contentKeywords.filter( + keyword => patch.includes(keyword) + ).length; + + if (businessKeywordCount > qaKeywordCount) { + businessLogicScore += businessKeywordCount * 0.1; + if (businessKeywordCount > 3) { + businessLogicSignals.push(`Business logic code patterns in ${filename}`); + } + } else if (qaKeywordCount > businessKeywordCount) { + qaTestingScore += qaKeywordCount * 0.1; + if (qaKeywordCount > 3) { + qaTestingSignals.push(`Test code patterns in ${filename}`); + } + } + } + } + + // Calculate total score and confidence + const totalScore = businessLogicScore + qaTestingScore; + const businessLogicRatio = totalScore > 0 ? businessLogicScore / totalScore : 0; + const qaTestingRatio = totalScore > 0 ? qaTestingScore / totalScore : 0; + + // Determine project type based on ratios + let projectType: 'business_logic' | 'qa_testing' | 'mixed' | 'unknown'; + let confidence: number; + + if (totalScore === 0) { + projectType = 'unknown'; + confidence = 0; + } else if (businessLogicRatio >= 0.8) { + projectType = 'business_logic'; + confidence = businessLogicRatio; + } else if (qaTestingRatio >= 0.8) { + projectType = 'qa_testing'; + confidence = qaTestingRatio; + } else { + projectType = 'mixed'; + confidence = 1 - Math.abs(businessLogicRatio - qaTestingRatio); + } + + // Generate type-specific recommendations + const recommendations = generateRecommendations(projectType, { + businessLogicScore, + qaTestingScore, + changedFilesCount: changedFiles.length, + }); + + return { + projectType, + confidence, + signals: { + businessLogicSignals, + qaTestingSignals, + }, + recommendations, + }; +} + +/** + * Generate recommendations based on project type + */ +function generateRecommendations( + projectType: 'business_logic' | 'qa_testing' | 'mixed' | 'unknown', + context: { + businessLogicScore: number; + qaTestingScore: number; + changedFilesCount: number; + } +): string[] { + const recommendations: string[] = []; + + switch (projectType) { + case 'business_logic': + recommendations.push( + '📋 **Business Logic Project Detected** - Focus on architecture and data flow review', + '🔒 Ensure proper input validation and error handling for business rules', + '⚡ Consider performance implications for data processing and API endpoints', + '🔐 Review authentication and authorization for sensitive business operations', + '📊 Verify data model changes are properly migrated and validated' + ); + + if (context.businessLogicScore > 10) { + recommendations.push('⚠️ Large business logic change - consider breaking into smaller PRs'); + } + break; + + case 'qa_testing': + recommendations.push( + '🧪 **QA/Testing Project Detected** - Focus on test quality and coverage', + '✅ Ensure tests are comprehensive and cover edge cases', + '🎯 Verify test assertions are meaningful and specific', + '♻️ Check for test maintainability and clear test descriptions', + '🚀 Consider test execution time and potential for flakiness' + ); + + if (context.qaTestingScore > 10) { + recommendations.push('📈 Extensive test changes - ensure all tests are passing and stable'); + } + break; + + case 'mixed': + recommendations.push( + '🔀 **Mixed Project Type** - Changes span both business logic and tests', + '🔄 Ensure business logic changes are properly covered by test changes', + '⚖️ Verify test changes reflect the business logic modifications', + '📝 Consider separating business logic and test changes into separate commits for clarity' + ); + break; + + case 'unknown': + recommendations.push( + '❓ **Project Type Unknown** - Unable to determine primary focus', + '🔍 Consider adding more context to file organization', + '📚 Review if changes follow project structure conventions' + ); + break; + } + + return recommendations; +} + +/** + * Format classification results for display + */ +export function formatClassification(classification: ProjectClassification): string { + const { projectType, confidence, signals, recommendations } = classification; + + let output = `\n## 🏗️ Project Classification\n\n`; + + // Project type badge + const typeEmoji = { + business_logic: '💼', + qa_testing: '🧪', + mixed: '🔀', + unknown: '❓', + }; + + const typeName = { + business_logic: 'Business Logic', + qa_testing: 'QA/Testing', + mixed: 'Mixed', + unknown: 'Unknown', + }; + + output += `**Type:** ${typeEmoji[projectType]} ${typeName[projectType]}\n`; + output += `**Confidence:** ${(confidence * 100).toFixed(0)}%\n\n`; + + // Signals + if (signals.businessLogicSignals.length > 0 || signals.qaTestingSignals.length > 0) { + output += `### 🔍 Detection Signals\n\n`; + + if (signals.businessLogicSignals.length > 0) { + output += `**Business Logic Indicators:**\n`; + signals.businessLogicSignals.slice(0, 5).forEach(signal => { + output += ` - ${signal}\n`; + }); + if (signals.businessLogicSignals.length > 5) { + output += ` - ...and ${signals.businessLogicSignals.length - 5} more\n`; + } + output += `\n`; + } + + if (signals.qaTestingSignals.length > 0) { + output += `**QA/Testing Indicators:**\n`; + signals.qaTestingSignals.slice(0, 5).forEach(signal => { + output += ` - ${signal}\n`; + }); + if (signals.qaTestingSignals.length > 5) { + output += ` - ...and ${signals.qaTestingSignals.length - 5} more\n`; + } + output += `\n`; + } + } + + // Recommendations + if (recommendations.length > 0) { + output += `### 💡 Type-Specific Recommendations\n\n`; + recommendations.forEach(rec => { + output += `${rec}\n\n`; + }); + } + + return output; +} + +/** + * LangChain tool for project classification + */ +export function createProjectClassifierTool() { + return new DynamicStructuredTool({ + name: 'classify_project_type', + description: + 'Classifies the project type (business logic vs QA/testing) based on changed files. ' + + 'This helps tailor the PR review to focus on the most relevant aspects. ' + + 'Use this early in the analysis to understand the project context.', + schema: z.object({ + changedFiles: z.array(z.object({ + filename: z.string().describe('The file path'), + patch: z.string().optional().describe('The git diff patch content'), + })).describe('Array of changed files with their content'), + }), + func: async ({ changedFiles }) => { + const classification = classifyProject(changedFiles); + return formatClassification(classification); + }, + }); +} diff --git a/src/tools/test-suggestion-tool.ts b/src/tools/test-suggestion-tool.ts new file mode 100644 index 0000000..e73fb2f --- /dev/null +++ b/src/tools/test-suggestion-tool.ts @@ -0,0 +1,591 @@ +/** + * Test Suggestion Tool for PR Analysis + * Generates test code suggestions for code changes without corresponding tests + */ + +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; +import fs from 'node:fs'; +import path from 'node:path'; + +/** + * Detect test framework from project configuration + */ +export function detectTestFramework(repoPath: string = '.'): { + framework: 'jest' | 'mocha' | 'vitest' | 'pytest' | 'unittest' | 'other'; + detected: boolean; + configFile?: string; +} { + const packageJsonPath = path.join(repoPath, 'package.json'); + + // Check for Node.js project + if (fs.existsSync(packageJsonPath)) { + try { + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); + const deps = { + ...packageJson.dependencies, + ...packageJson.devDependencies, + }; + + // Check for Jest + if (deps.jest || deps['@jest/core'] || fs.existsSync(path.join(repoPath, 'jest.config.js')) || fs.existsSync(path.join(repoPath, 'jest.config.ts'))) { + return { framework: 'jest', detected: true, configFile: 'jest.config.js' }; + } + + // Check for Vitest + if (deps.vitest || fs.existsSync(path.join(repoPath, 'vitest.config.js')) || fs.existsSync(path.join(repoPath, 'vitest.config.ts'))) { + return { framework: 'vitest', detected: true, configFile: 'vitest.config.js' }; + } + + // Check for Mocha + if (deps.mocha || fs.existsSync(path.join(repoPath, '.mocharc.js')) || fs.existsSync(path.join(repoPath, '.mocharc.json'))) { + return { framework: 'mocha', detected: true, configFile: '.mocharc.js' }; + } + } catch (e) { + // Ignore JSON parse errors + } + } + + // Check for Python project + const pytestIni = path.join(repoPath, 'pytest.ini'); + const pyprojectToml = path.join(repoPath, 'pyproject.toml'); + const setupPy = path.join(repoPath, 'setup.py'); + + if (fs.existsSync(pytestIni)) { + return { framework: 'pytest', detected: true, configFile: 'pytest.ini' }; + } + + if (fs.existsSync(pyprojectToml)) { + try { + const content = fs.readFileSync(pyprojectToml, 'utf-8'); + if (content.includes('[tool.pytest]') || content.includes('pytest')) { + return { framework: 'pytest', detected: true, configFile: 'pyproject.toml' }; + } + } catch (e) { + // Ignore read errors + } + } + + if (fs.existsSync(setupPy)) { + try { + const content = fs.readFileSync(setupPy, 'utf-8'); + if (content.includes('pytest')) { + return { framework: 'pytest', detected: true, configFile: 'setup.py' }; + } + } catch (e) { + // Ignore read errors + } + } + + return { framework: 'other', detected: false }; +} + +/** + * Check if a file is a test file + */ +export function isTestFile(filePath: string): boolean { + const testPatterns = [ + /\.test\.[jt]sx?$/, + /\.spec\.[jt]sx?$/, + /_test\.py$/, + /test_.*\.py$/, + /\.test\.go$/, + /_test\.go$/, + /Test\.java$/, + /\.test\.rs$/, + ]; + + return testPatterns.some(pattern => pattern.test(filePath)); +} + +/** + * Check if a file is a code file that should have tests + */ +export function isCodeFile(filePath: string): boolean { + const codeExtensions = ['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.java', '.rs', '.rb', '.cs']; + const ext = path.extname(filePath).toLowerCase(); + + // Exclude config files, type definitions, etc. + if (filePath.includes('.d.ts') || filePath.includes('.config.') || filePath.includes('index.')) { + return false; + } + + return codeExtensions.includes(ext); +} + +/** + * Generate test file path suggestion + */ +export function suggestTestFilePath(sourceFilePath: string, framework: string): string { + const ext = path.extname(sourceFilePath); + const baseName = path.basename(sourceFilePath, ext); + const dirName = path.dirname(sourceFilePath); + + // For TypeScript/JavaScript + if (['.ts', '.tsx', '.js', '.jsx'].includes(ext)) { + if (framework === 'jest' || framework === 'vitest') { + // Check if there's a __tests__ folder pattern + if (dirName.includes('src')) { + const testsDir = dirName.replace('src', 'tests'); + return path.join(testsDir, `${baseName}.test${ext}`); + } + return path.join(dirName, `${baseName}.test${ext}`); + } + if (framework === 'mocha') { + return path.join(dirName, `${baseName}.spec${ext}`); + } + } + + // For Python + if (ext === '.py') { + return path.join(dirName, `test_${baseName}.py`); + } + + // For Go + if (ext === '.go') { + return path.join(dirName, `${baseName}_test.go`); + } + + // Default + return path.join(dirName, `${baseName}.test${ext}`); +} + +/** + * Create test suggestion tool + */ +export function createTestSuggestionTool() { + return new DynamicStructuredTool({ + name: 'suggest_tests', + description: 'Analyze code changes and suggest tests for files without test coverage', + schema: z.object({ + files: z.array(z.object({ + path: z.string(), + diff: z.string(), + additions: z.number(), + })).describe('Array of changed files to analyze'), + framework: z.string().optional().describe('Test framework to use'), + repoPath: z.string().optional().describe('Repository path for framework detection'), + }), + func: async ({ files, framework: providedFramework, repoPath }) => { + const detectedFramework = detectTestFramework(repoPath || '.'); + const testFramework = providedFramework || detectedFramework.framework; + + // Filter to code files only + const codeFiles = files.filter(f => isCodeFile(f.path) && !isTestFile(f.path)); + + // Check if corresponding test files exist in the PR + const testFilesInPR = files.filter(f => isTestFile(f.path)).map(f => f.path); + + const filesNeedingTests: Array<{ + file: string; + hasPRTest: boolean; + suggestedTestPath: string; + codeSnippet: string; + }> = []; + + for (const file of codeFiles) { + // Check if a test for this file is included in the PR + const baseNameWithoutExt = path.basename(file.path, path.extname(file.path)); + const hasPRTest = testFilesInPR.some(testPath => + testPath.toLowerCase().includes(baseNameWithoutExt.toLowerCase()) + ); + + if (!hasPRTest && file.additions > 5) { // Only suggest for files with significant changes + // Extract added code from diff + const addedLines = file.diff + .split('\n') + .filter(line => line.startsWith('+') && !line.startsWith('+++')) + .map(line => line.substring(1)) + .join('\n'); + + filesNeedingTests.push({ + file: file.path, + hasPRTest: false, + suggestedTestPath: suggestTestFilePath(file.path, testFramework), + codeSnippet: addedLines.substring(0, 1000), // Limit for context + }); + } + } + + return JSON.stringify({ + testFramework, + frameworkDetected: detectedFramework.detected, + configFile: detectedFramework.configFile, + filesAnalyzed: codeFiles.length, + filesNeedingTests: filesNeedingTests.length, + files: filesNeedingTests, + }); + }, + }); +} + +/** + * Generate test code template based on framework and code + */ +export function generateTestTemplate( + framework: string, + filePath: string, + codeSnippet: string, + functionNames: string[] = [] +): string { + const baseName = path.basename(filePath, path.extname(filePath)); + const modulePath = filePath.replace(/\.[^/.]+$/, ''); + + switch (framework) { + case 'jest': + case 'vitest': + return `import { describe, it, expect } from '${framework === 'vitest' ? 'vitest' : '@jest/globals'}'; +import { /* exported functions */ } from '${modulePath}'; + +describe('${baseName}', () => { +${functionNames.map(fn => ` describe('${fn}', () => { + it('should work correctly', () => { + // TODO: Add test implementation + expect(true).toBe(true); + }); + + it('should handle edge cases', () => { + // TODO: Add edge case tests + }); + }); +`).join('\n') || ` it('should be implemented', () => { + // TODO: Add tests for ${baseName} + expect(true).toBe(true); + }); +`} +}); +`; + + case 'mocha': + return `const { expect } = require('chai'); +const { /* exported functions */ } = require('${modulePath}'); + +describe('${baseName}', function() { +${functionNames.map(fn => ` describe('${fn}', function() { + it('should work correctly', function() { + // TODO: Add test implementation + expect(true).to.be.true; + }); + }); +`).join('\n') || ` it('should be implemented', function() { + // TODO: Add tests for ${baseName} + expect(true).to.be.true; + }); +`} +}); +`; + + case 'pytest': + return `import pytest +from ${modulePath.replace(/\//g, '.')} import * + +class Test${baseName.charAt(0).toUpperCase() + baseName.slice(1)}: +${functionNames.map(fn => ` def test_${fn}_works(self): + """Test that ${fn} works correctly.""" + # TODO: Add test implementation + assert True + + def test_${fn}_edge_cases(self): + """Test ${fn} edge cases.""" + # TODO: Add edge case tests + assert True +`).join('\n') || ` def test_implementation(self): + """Test ${baseName} functionality.""" + # TODO: Add tests + assert True +`} +`; + + default: + return `// TODO: Add tests for ${baseName} +// Detected framework: ${framework} +// +// Test the following functionality: +${functionNames.map(fn => `// - ${fn}`).join('\n') || '// - Main module functionality'} +`; + } +} + +/** + * Test Enhancement Suggestion - analyzes existing tests and suggests improvements + */ +export interface TestEnhancement { + testFile: string; + sourceFile: string; + currentTests: string[]; + missingScenarios: string[]; + suggestions: string[]; + enhancementCode?: string; +} + +/** + * Analyze existing test file and suggest enhancements + */ +export function analyzeTestQuality( + testFile: { path: string; diff: string }, + sourceFile: { path: string; diff: string }, + framework: string +): TestEnhancement { + const testContent = testFile.diff; + const sourceContent = sourceFile.diff; + + // Extract existing test cases from the test file + const currentTests: string[] = []; + const testPatterns = [ + /(?:test|it|describe)\s*\(\s*['"`]([^'"`]+)['"`]/g, // Jest/Mocha/Vitest + /def\s+test_(\w+)/g, // Python + ]; + + for (const pattern of testPatterns) { + let match; + while ((match = pattern.exec(testContent)) !== null) { + currentTests.push(match[1]); + } + } + + // Analyze source code to identify testable scenarios + const missingScenarios: string[] = []; + const suggestions: string[] = []; + + // Check for common missing test scenarios + + // 1. Error handling tests + if (sourceContent.includes('throw ') || sourceContent.includes('raise ') || + sourceContent.includes('Error(') || sourceContent.includes('Exception(')) { + const hasErrorTests = currentTests.some(t => + /error|exception|throw|fail|invalid/i.test(t) + ); + if (!hasErrorTests) { + missingScenarios.push('Error handling tests'); + suggestions.push('⚠️ Add tests for error conditions and exception handling'); + } + } + + // 2. Edge case tests + const hasEdgeCaseTests = currentTests.some(t => + /edge|boundary|limit|empty|null|zero|max|min/i.test(t) + ); + if (!hasEdgeCaseTests && sourceContent.length > 100) { + missingScenarios.push('Edge case tests'); + suggestions.push('🔍 Add tests for edge cases (null, undefined, empty, boundary values)'); + } + + // 3. Async operation tests + if ((sourceContent.includes('async ') || sourceContent.includes('await ') || + sourceContent.includes('Promise') || sourceContent.includes('.then(')) && + !testContent.includes('async ')) { + missingScenarios.push('Async operation tests'); + suggestions.push('⏱️ Add async/await tests for asynchronous operations'); + } + + // 4. Input validation tests + if (sourceContent.includes('validate') || sourceContent.includes('check') || + sourceContent.match(/if\s*\(/)) { + const hasValidationTests = currentTests.some(t => + /valid|invalid|check|verify/i.test(t) + ); + if (!hasValidationTests) { + missingScenarios.push('Input validation tests'); + suggestions.push('✅ Add tests for input validation and type checking'); + } + } + + // 5. Return value tests + const hasReturnTests = currentTests.some(t => + /return|result|output|expect/i.test(t) + ); + if (!hasReturnTests && (sourceContent.includes('return ') || sourceContent.includes('yield '))) { + missingScenarios.push('Return value verification'); + suggestions.push('🎯 Add explicit tests for expected return values and types'); + } + + // 6. Side effects and state changes + if (sourceContent.match(/\.\w+\s*=/g) || sourceContent.includes('setState') || + sourceContent.includes('this.')) { + const hasStateTests = currentTests.some(t => + /state|change|update|mutate/i.test(t) + ); + if (!hasStateTests) { + missingScenarios.push('State change tests'); + suggestions.push('🔄 Add tests to verify state changes and side effects'); + } + } + + // 7. Integration/interaction tests + if (sourceContent.includes('import ') && currentTests.length < 3) { + suggestions.push('🔗 Consider adding integration tests for component interactions'); + } + + // Generate enhancement code suggestions + let enhancementCode = ''; + if (missingScenarios.length > 0) { + enhancementCode = generateEnhancementCode(framework, testFile.path, missingScenarios); + } + + return { + testFile: testFile.path, + sourceFile: sourceFile.path, + currentTests, + missingScenarios, + suggestions, + enhancementCode, + }; +} + +/** + * Generate code for test enhancements + */ +function generateEnhancementCode( + framework: string, + testFilePath: string, + missingScenarios: string[] +): string { + const baseName = path.basename(testFilePath, path.extname(testFilePath)); + + switch (framework) { + case 'jest': + case 'vitest': + return ` +// === Suggested Test Enhancements === + +${missingScenarios.includes('Error handling tests') ? ` +describe('Error Handling', () => { + it('should handle invalid input gracefully', () => { + expect(() => functionName(null)).toThrow(); + expect(() => functionName(undefined)).toThrow(); + }); + + it('should throw appropriate error for edge cases', () => { + expect(() => functionName('')).toThrow('Invalid input'); + }); +}); +` : ''} + +${missingScenarios.includes('Edge case tests') ? ` +describe('Edge Cases', () => { + it('should handle empty input', () => { + expect(functionName('')).toBe(expectedEmptyResult); + }); + + it('should handle null and undefined', () => { + expect(functionName(null)).toBe(null); + expect(functionName(undefined)).toBe(undefined); + }); + + it('should handle boundary values', () => { + expect(functionName(0)).toBe(expectedZeroResult); + expect(functionName(Number.MAX_VALUE)).toBeDefined(); + }); +}); +` : ''} + +${missingScenarios.includes('Async operation tests') ? ` +describe('Async Operations', () => { + it('should resolve successfully', async () => { + const result = await asyncFunction(); + expect(result).toBeDefined(); + }); + + it('should handle async errors', async () => { + await expect(asyncFunction('invalid')).rejects.toThrow(); + }); +}); +` : ''} +`; + + case 'mocha': + return ` +// === Suggested Test Enhancements === + +${missingScenarios.includes('Error handling tests') ? ` +describe('Error Handling', function() { + it('should handle invalid input gracefully', function() { + expect(() => functionName(null)).to.throw(); + }); +}); +` : ''} + +${missingScenarios.includes('Edge case tests') ? ` +describe('Edge Cases', function() { + it('should handle empty input', function() { + expect(functionName('')).to.equal(expectedEmptyResult); + }); + + it('should handle boundary values', function() { + expect(functionName(0)).to.be.defined; + }); +}); +` : ''} +`; + + case 'pytest': + case 'unittest': + return ` +# === Suggested Test Enhancements === + +${missingScenarios.includes('Error handling tests') ? ` +def test_error_handling(): + """Test error handling with invalid inputs.""" + with pytest.raises(ValueError): + function_name(None) + with pytest.raises(ValueError): + function_name('') +` : ''} + +${missingScenarios.includes('Edge case tests') ? ` +def test_edge_cases(): + """Test edge cases and boundary conditions.""" + assert function_name('') == expected_empty_result + assert function_name(0) == expected_zero_result + assert function_name(None) is None +` : ''} + +${missingScenarios.includes('Async operation tests') ? ` +@pytest.mark.asyncio +async def test_async_operations(): + """Test asynchronous operations.""" + result = await async_function() + assert result is not None +` : ''} +`; + + default: + return `// Consider adding tests for: ${missingScenarios.join(', ')}`; + } +} + +/** + * Format test enhancement for display + */ +export function formatTestEnhancement(enhancement: TestEnhancement): string { + let output = `\n### 🔬 Test Enhancement: ${path.basename(enhancement.testFile)}\n\n`; + + output += `**Source File:** ${enhancement.sourceFile}\n`; + output += `**Current Tests:** ${enhancement.currentTests.length} test case(s)\n\n`; + + if (enhancement.currentTests.length > 0 && enhancement.currentTests.length <= 5) { + output += `**Existing Tests:**\n`; + enhancement.currentTests.forEach(test => { + output += ` ✓ ${test}\n`; + }); + output += `\n`; + } + + if (enhancement.missingScenarios.length > 0) { + output += `**Missing Test Scenarios:**\n`; + enhancement.missingScenarios.forEach(scenario => { + output += ` ⚠️ ${scenario}\n`; + }); + output += `\n`; + } + + if (enhancement.suggestions.length > 0) { + output += `**Recommendations:**\n`; + enhancement.suggestions.forEach(suggestion => { + output += ` ${suggestion}\n`; + }); + output += `\n`; + } + + return output; +} diff --git a/src/types.ts b/src/types.ts index c2d1c97..136370a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,7 @@ // PR Agent - Basic Types // Core types for PR analysis -export type AIProviderType = 'anthropic' | 'openai' | 'google'; +export type AIProviderType = 'anthropic' | 'openai' | 'google' | 'zhipu'; export interface PRInfo { number: number; diff --git a/src/types/agent.types.ts b/src/types/agent.types.ts index 75ff0e4..556a0d3 100644 --- a/src/types/agent.types.ts +++ b/src/types/agent.types.ts @@ -48,6 +48,47 @@ export interface AnalysisMode { complexity: boolean; } +/** + * Execution mode for LLM-agnostic operation + */ +export enum ExecutionMode { + EXECUTE = 'execute', // CLI: Execute prompts with API key + PROMPT_ONLY = 'prompt_only', // MCP: Return prompts for calling LLM +} + +/** + * Individual analysis prompt for PROMPT_ONLY mode + * Supports both main PR analysis and peer review prompts + */ +export interface AnalysisPrompt { + step: 'fileAnalysis' | 'riskDetection' | 'summaryGeneration' | 'selfRefinement' | 'ticketQuality' | 'acValidation' | 'peerReview'; + prompt: string; // The filled-in prompt template + context?: Record; // Additional context (main analysis) + instructions: string; // How to execute this prompt + // Fields for peer review prompts (optional) + schema?: any; // Zod schema for structured output + formatInstructions?: string; // Format instructions for output + inputs?: Record; // Input variables +} + +/** + * Result when in PROMPT_ONLY mode - returns prompts instead of executing them + * Also includes static analysis results that don't require an LLM + */ +export interface PromptOnlyResult { + mode: 'prompt_only'; + context: AgentContext; // All input data + prompts: AnalysisPrompt[]; // Prompts for calling LLM + instructions: string; // How to execute all prompts + // Static analysis results (run immediately, no LLM needed) + staticAnalysis?: { + testSuggestions?: TestSuggestion[]; + devOpsCostEstimates?: DevOpsCostEstimate[]; + coverageReport?: CoverageReport; + projectClassification?: string; + }; +} + export interface RiskItem { description: string; archDocsReference?: { @@ -57,6 +98,60 @@ export interface RiskItem { }; } +/** + * Code suggestion for fixing issues found during review + */ +export interface CodeSuggestion { + filePath: string; + lineRange: { start: number; end: number }; + originalCode: string; + suggestedCode: string; + reason: string; +} + +/** + * Test suggestion for code without tests + */ +export interface TestSuggestion { + forFile: string; + testFramework: 'jest' | 'mocha' | 'vitest' | 'pytest' | 'unittest' | 'other'; + testCode: string; + description: string; + testFilePath?: string; // Suggested path for the test file + isEnhancement?: boolean; // True if this is an enhancement to existing tests + existingTestFile?: string; // Path to existing test file being enhanced +} + +/** + * DevOps cost estimate for infrastructure changes + */ +export interface DevOpsCostEstimate { + resource: string; + resourceType: string; // e.g., 'EC2', 'Lambda', 'S3', 'RDS' + currentMonthlyCost?: number; + estimatedNewCost: number; + difference?: number; + confidence: 'high' | 'medium' | 'low'; + details?: string; +} + +/** + * Test coverage report + */ +export interface CoverageReport { + available: boolean; + overallPercentage?: number; + lineCoverage?: number; + branchCoverage?: number; + fileBreakdown?: Array<{ + file: string; + lineCoverage: number; + branchCoverage?: number; + }>; + delta?: number; // Change in coverage compared to baseline + coverageTool?: string; // e.g., 'jest', 'nyc', 'coverage.py' +} + export interface FileAnalysis { path: string; summary: string; @@ -67,6 +162,7 @@ export interface FileAnalysis { deletions: number; }; recommendations: string[]; + suggestedChanges?: CodeSuggestion[]; // Specific code fix suggestions } export interface Fix { @@ -89,6 +185,8 @@ export interface AgentResult { totalTokensUsed: number; executionTime: number; mode: AnalysisMode; + overallComplexity?: number; + overallRisks?: string[]; archDocsImpact?: { used: boolean; docsAvailable: number; @@ -103,8 +201,19 @@ export interface AgentResult { warningCount: number; criticalIssues: string[]; }; + // Enhanced analysis features (v0.2.0) + testSuggestions?: TestSuggestion[]; + devOpsCostEstimates?: DevOpsCostEstimate[]; + coverageReport?: CoverageReport; + // Project classification (v0.3.0) + projectClassification?: string; } +/** + * Union type for agent results - either executed results or prompts to execute + */ +export type AgentResultOrPrompts = AgentResult | PromptOnlyResult; + // Alias for backward compatibility export type AgentAnalysisResult = AgentResult; diff --git a/src/types/issue-tracker.types.ts b/src/types/issue-tracker.types.ts new file mode 100644 index 0000000..6577ef5 --- /dev/null +++ b/src/types/issue-tracker.types.ts @@ -0,0 +1,211 @@ +/** + * Generic Issue Tracker Provider Interface + * + * This abstraction allows PR Agent to work with different issue tracking systems + * (Jira, Linear, Azure DevOps, GitHub Issues, etc.) through a unified interface. + * + * MVP: Jira implementation via Atlassian MCP + * Future: Linear, Azure DevOps, GitHub Issues, etc. + */ + +/** + * Normalized ticket/issue representation across all providers + */ +export interface IssueTicket { + // Core identifiers + id: string; // Provider-specific ID + key: string; // Human-readable key (e.g., "PROJ-123", "#456") + url: string; // Direct link to the ticket + + // Basic info + title: string; + description: string; + type: IssueType; + status: string; + priority: IssuePriority; + + // People + assignee?: string; + reporter?: string; + + // Categorization + labels: string[]; + components: string[]; + project?: string; + + // Estimates + storyPoints?: number; + estimate?: string; + + // Acceptance criteria - the key field for Peer Review Agent + acceptanceCriteria?: string; + acceptanceCriteriaList?: string[]; + + // Test information + testScenarios?: string[]; + linkedTestCases?: string[]; + + // Attachments and context + hasScreenshots: boolean; + hasDiagrams: boolean; + attachmentCount: number; + + // Relations + parentKey?: string; + epicKey?: string; + linkedIssues: LinkedIssue[]; + subtasks: SubtaskInfo[]; + + // Timestamps + createdAt: string; + updatedAt: string; + + // Raw provider-specific data for edge cases + rawData?: Record; +} + +export type IssueType = + | 'bug' + | 'feature' + | 'story' + | 'task' + | 'epic' + | 'subtask' + | 'improvement' + | 'spike' + | 'other'; + +export type IssuePriority = + | 'critical' + | 'high' + | 'medium' + | 'low' + | 'none'; + +export interface LinkedIssue { + key: string; + type: string; // "blocks", "is blocked by", "relates to", "duplicates", etc. + title: string; + status: string; +} + +export interface SubtaskInfo { + key: string; + title: string; + status: string; +} + +/** + * Reference to a ticket found in PR metadata + */ +export interface TicketReference { + key: string; + source: 'title' | 'description' | 'branch' | 'commit' | 'manual'; + rawMatch: string; // The actual text that matched + confidence: number; // 0-100 +} + +/** + * Issue tracker provider interface - implement this for each provider + */ +export interface IssueTrackerProvider { + /** + * Provider name for display and configuration + */ + readonly name: string; + + /** + * Provider type identifier + */ + readonly type: IssueTrackerType; + + /** + * Check if the provider is properly configured and accessible + */ + isConfigured(): boolean; + + /** + * Test connection to the provider + */ + testConnection(): Promise; + + /** + * Fetch a single ticket by key + */ + getTicket(key: string): Promise; + + /** + * Fetch multiple tickets by keys + */ + getTickets(keys: string[]): Promise; + + /** + * Extract ticket references from PR metadata + */ + extractTicketReferences(context: TicketExtractionContext): TicketReference[]; + + /** + * Search for tickets matching a query + */ + searchTickets?(query: string, limit?: number): Promise; + + /** + * Get ticket comments (if supported) + */ + getComments?(ticketKey: string): Promise; +} + +export type IssueTrackerType = + | 'jira' + | 'linear' + | 'azure-devops' + | 'github-issues' + | 'gitlab-issues' + | 'shortcut' + | 'asana' + | 'other'; + +export interface TicketExtractionContext { + prTitle: string; + prDescription?: string; + branchName?: string; + commitMessages?: string[]; +} + +export interface IssueComment { + id: string; + author: string; + body: string; + createdAt: string; +} + +/** + * Configuration for issue tracker integration + */ +export interface IssueTrackerConfig { + enabled: boolean; + provider: IssueTrackerType; + + // Provider-specific settings (varies by provider) + providerConfig: Record; + + // Analysis settings (common across providers) + analyzeAcceptanceCriteria: boolean; + rateTicketQuality: boolean; + generateTestSuggestions: boolean; + checkScopeCreep: boolean; + + // Ticket extraction patterns (regex) + ticketPatterns?: string[]; + + // Output settings + includeTicketDetails: boolean; + verbose: boolean; +} + +/** + * Factory function type for creating providers + */ +export type IssueTrackerProviderFactory = ( + config: IssueTrackerConfig +) => IssueTrackerProvider | null; diff --git a/src/types/jira.types.ts b/src/types/jira.types.ts new file mode 100644 index 0000000..3205d74 --- /dev/null +++ b/src/types/jira.types.ts @@ -0,0 +1,278 @@ +/** + * Jira types and interfaces for Peer Review Agent + * Provides structures for Jira ticket analysis and acceptance criteria validation + */ + +/** + * Jira ticket from the Atlassian API/MCP + */ +export interface JiraTicket { + key: string; // e.g., "PROJ-123" + id: string; // Jira internal ID + summary: string; // Ticket title + description: string; // Full description (may contain markdown/rich text) + status: string; // e.g., "In Progress", "In Review", "Done" + type: JiraTicketType; // bug, feature, task, story, epic + priority: string; // e.g., "High", "Medium", "Low" + assignee?: string; // Assignee display name + reporter?: string; // Reporter display name + labels: string[]; // Labels/tags + components: string[]; // Affected components + fixVersions: string[]; // Target release versions + storyPoints?: number; // Story points estimate + createdAt: string; // ISO date string + updatedAt: string; // ISO date string + + // Acceptance criteria - can be in description or custom field + acceptanceCriteria?: string; // Extracted AC text + acceptanceCriteriaItems?: AcceptanceCriteriaItem[]; + + // Test-related fields + testScenarios?: string[]; // Listed test scenarios + testCases?: string[]; // Linked test cases + + // Additional context + attachments?: JiraAttachment[]; + linkedIssues?: JiraLinkedIssue[]; + comments?: JiraComment[]; + subtasks?: JiraSubtask[]; + parentKey?: string; // If this is a subtask + epicKey?: string; // Parent epic + + // Raw fields for custom field access + customFields?: Record; +} + +export type JiraTicketType = 'bug' | 'feature' | 'task' | 'story' | 'epic' | 'subtask' | 'improvement' | 'other'; + +export interface AcceptanceCriteriaItem { + id: string; // Generated ID for tracking + text: string; // The AC text + isMet?: boolean; // Whether this AC is covered by the PR + coverageDetails?: string; // Explanation of how it's covered + relatedFiles?: string[]; // Files that implement this AC + confidence: number; // 0-100 confidence in assessment +} + +export interface JiraAttachment { + id: string; + filename: string; + mimeType: string; + url: string; + createdAt: string; + isScreenshot: boolean; +} + +export interface JiraLinkedIssue { + key: string; + type: string; // "blocks", "is blocked by", "relates to", etc. + summary: string; + status: string; +} + +export interface JiraComment { + id: string; + author: string; + body: string; + createdAt: string; +} + +export interface JiraSubtask { + key: string; + summary: string; + status: string; +} + +/** + * Ticket quality rating based on best practices + */ +export interface TicketQualityRating { + overallScore: number; // 0-100 composite score + + // Individual dimension scores (0-100) + dimensions: { + descriptionClarity: number; // Is the description clear and complete? + acceptanceCriteriaQuality: number; // Are ACs specific, measurable, testable? + testabilityScore: number; // Are test scenarios/cases defined? + scopeDefinition: number; // Is scope well-defined and bounded? + technicalContext: number; // Are technical details/constraints provided? + visualDocumentation: number; // Screenshots, diagrams, mockups? + estimationQuality: number; // Story points reasonable for scope? + completeness: number; // Overall ticket completeness + }; + + // Detailed feedback for each dimension + feedback: { + strengths: string[]; // What's good about the ticket + weaknesses: string[]; // What's missing or unclear + suggestions: string[]; // How to improve the ticket + }; + + // Quality tier based on score + tier: 'excellent' | 'good' | 'adequate' | 'poor' | 'insufficient'; + + // Can we provide meaningful PR review with this ticket? + reviewable: boolean; + reviewabilityReason: string; +} + +/** + * Result of acceptance criteria validation against PR changes + */ +export interface AcceptanceCriteriaValidation { + ticketKey: string; + totalCriteria: number; + metCriteria: number; + unmetCriteria: number; + partialCriteria: number; + + // Detailed per-criteria analysis + criteriaAnalysis: CriteriaAnalysisItem[]; + + // Overall compliance percentage + compliancePercentage: number; + + // Summary of gaps + gaps: AcceptanceCriteriaGap[]; + + // Suggested test scenarios for uncovered cases + suggestedTestScenarios: TestScenarioSuggestion[]; +} + +export interface CriteriaAnalysisItem { + criteriaId: string; + criteriaText: string; + status: 'met' | 'unmet' | 'partial' | 'unclear'; + confidence: number; // 0-100 + evidence: string[]; // Code snippets or file references that show coverage + explanation: string; // Why we think it's met/unmet + relatedFiles: string[]; // Files that relate to this criteria +} + +export interface AcceptanceCriteriaGap { + criteriaText: string; + gapDescription: string; + severity: 'critical' | 'major' | 'minor'; + suggestedAction: string; +} + +export interface TestScenarioSuggestion { + scenario: string; // Test scenario description + type: 'unit' | 'integration' | 'e2e' | 'manual'; + priority: 'high' | 'medium' | 'low'; + relatedCriteria: string[]; // Which AC this tests + suggestedApproach: string; // How to implement the test +} + +/** + * Complete Jira analysis result for a PR + */ +export interface JiraAnalysisResult { + // Linked tickets found in PR + linkedTickets: JiraTicket[]; + primaryTicket?: JiraTicket; // Main ticket (first found or specified) + + // Ticket quality assessment + ticketQuality?: TicketQualityRating; + + // Acceptance criteria validation + acValidation?: AcceptanceCriteriaValidation; + + // Cross-reference with PR changes + scopeAnalysis: { + inScope: string[]; // Changes that align with ticket scope + outOfScope: string[]; // Changes that seem unrelated + scopeCreepRisk: boolean; + scopeCreepDetails?: string; + }; + + // Edge cases and test coverage + edgeCaseAnalysis: { + identifiedEdgeCases: string[]; + coveredEdgeCases: string[]; + uncoveredEdgeCases: string[]; + testSuggestions: TestScenarioSuggestion[]; + }; + + // Overall assessment + overallAssessment: { + implementationCompleteness: number; // 0-100 + qualityScore: number; // 0-100 + readyForReview: boolean; + blockers: string[]; + warnings: string[]; + recommendations: string[]; + }; + + // Metrics summary + metrics: { + ticketsCovered: number; + criteriaTotal: number; + criteriaMet: number; + criteriaPartial: number; + criteriaUnmet: number; + testScenariosGenerated: number; + }; +} + +/** + * Configuration for Jira integration + */ +export interface JiraConfig { + enabled: boolean; + + // MCP connection settings + mcpServerUrl?: string; // If using custom MCP server + + // Jira instance settings (for direct API if needed) + instanceUrl?: string; // e.g., "https://company.atlassian.net" + projectKey?: string; // Default project key + + // Authentication (via MCP or direct) + apiToken?: string; // Jira API token + email?: string; // Jira account email + + // Analysis settings + analyzeAcceptanceCriteria: boolean; + rateTicketQuality: boolean; + generateTestSuggestions: boolean; + checkScopeCreep: boolean; + + // Output settings + includeTicketDetailsInOutput: boolean; + verboseOutput: boolean; +} + +/** + * Ticket reference extracted from PR title/description/branch + */ +export interface TicketReference { + key: string; // e.g., "PROJ-123" + source: 'title' | 'description' | 'branch' | 'commit'; + confidence: number; // How confident we are this is the right ticket +} + +/** + * Context passed to Jira sub-agent + */ +export interface JiraAnalysisContext { + prTitle: string; + prDescription?: string; + branchName?: string; + commitMessages?: string[]; + diff: string; + files: Array<{ + path: string; + additions: number; + deletions: number; + status: string; + }>; + + // Pre-analyzed PR data + prSummary?: string; + prRisks?: string[]; + prComplexity?: number; + + // Jira config + config: JiraConfig; +} diff --git a/src/utils/config-validator.ts b/src/utils/config-validator.ts index 9e00c6a..5d24413 100644 --- a/src/utils/config-validator.ts +++ b/src/utils/config-validator.ts @@ -15,11 +15,12 @@ export const UserConfigSchema = z.object({ anthropic: z.string().optional(), openai: z.string().optional(), google: z.string().optional(), + zhipu: z.string().optional(), }) .optional(), ai: z .object({ - provider: z.enum(['anthropic', 'openai', 'google']).optional(), + provider: z.enum(['anthropic', 'openai', 'google', 'zhipu']).optional(), model: z.string().optional(), temperature: z.number().min(0).max(2).optional(), maxTokens: z.number().positive().int().optional(), @@ -66,6 +67,26 @@ export const UserConfigSchema = z.object({ showRecommendations: z.boolean().optional(), }) .optional(), + peerReview: z + .object({ + enabled: z.boolean().optional(), + provider: z.string().optional(), + useMcp: z.boolean().optional(), + instanceUrl: z.string().url().optional(), + email: z.string().email().optional(), + apiToken: z.string().optional(), + defaultProject: z.string().optional(), + acceptanceCriteriaField: z.string().optional(), + storyPointsField: z.string().optional(), + ticketPatterns: z.array(z.string()).optional(), + analyzeAcceptanceCriteria: z.boolean().optional(), + rateTicketQuality: z.boolean().optional(), + generateTestSuggestions: z.boolean().optional(), + checkScopeCreep: z.boolean().optional(), + includeTicketDetails: z.boolean().optional(), + verbose: z.boolean().optional(), + }) + .optional(), }); /** diff --git a/src/utils/output-formatter.ts b/src/utils/output-formatter.ts new file mode 100644 index 0000000..783a6cb --- /dev/null +++ b/src/utils/output-formatter.ts @@ -0,0 +1,371 @@ +/** + * Shared output formatting for CLI and MCP server + * Supports both terminal (chalk colors) and markdown output modes + */ + +import chalk from 'chalk'; +import type { Fix } from '../types/agent.types.js'; + +export type OutputMode = 'terminal' | 'markdown'; + +export interface FormatterOptions { + mode: OutputMode; + verbose?: boolean; +} + +/** + * Output formatter that can generate terminal or markdown output + */ +export class OutputFormatter { + private mode: OutputMode; + private verbose: boolean; + + constructor(options: FormatterOptions) { + this.mode = options.mode; + this.verbose = options.verbose || false; + } + + /** + * Format a section separator line + */ + separator(): string { + if (this.mode === 'markdown') { + return '\n---\n'; + } + return chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + } + + /** + * Format a bold title + */ + bold(text: string): string { + if (this.mode === 'markdown') { + return `**${text}**`; + } + return chalk.bold(text); + } + + /** + * Format a colored title + */ + title(text: string, color: 'green' | 'cyan' | 'yellow' | 'blue' | 'red' = 'cyan'): string { + if (this.mode === 'markdown') { + return `## ${text}`; + } + const chalkColor = chalk[color].bold; + return chalkColor(text); + } + + /** + * Format regular text + */ + text(text: string): string { + if (this.mode === 'markdown') { + return text; + } + return chalk.white(text); + } + + /** + * Format gray/dimmed text + */ + dim(text: string): string { + if (this.mode === 'markdown') { + return text; + } + return chalk.gray(text); + } + + /** + * Format test suggestions section + */ + formatTestSuggestions(testSuggestions: any[]): string { + if (!testSuggestions || testSuggestions.length === 0) { + return ''; + } + + const lines: string[] = []; + const newTests = testSuggestions.filter((s: any) => !s.isEnhancement); + const enhancements = testSuggestions.filter((s: any) => s.isEnhancement); + + // New test suggestions + if (newTests.length > 0) { + lines.push(this.separator()); + lines.push(''); + + if (this.mode === 'markdown') { + lines.push(`### 🧪 Test Suggestions (${newTests.length})`); + } else { + lines.push(chalk.yellow.bold(`🧪 Test Suggestions (${newTests.length} files need tests)`)); + } + lines.push(''); + + for (const suggestion of newTests) { + if (this.mode === 'markdown') { + lines.push(`**${suggestion.forFile}**`); + lines.push(`- Framework: ${suggestion.testFramework}`); + if (suggestion.testFilePath) { + lines.push(`- Suggested path: ${suggestion.testFilePath}`); + } + lines.push(''); + } else { + lines.push(chalk.cyan(` 📝 ${suggestion.forFile}`)); + lines.push(chalk.gray(` Framework: ${suggestion.testFramework}`)); + if (suggestion.testFilePath) { + lines.push(chalk.gray(` Suggested test file: ${suggestion.testFilePath}`)); + } + lines.push(chalk.white(` ${suggestion.description}`)); + lines.push(''); + + // Show test code preview for terminal + if (suggestion.testCode) { + lines.push(chalk.gray(' ┌─────────────────────────────────────────')); + const codeLines = suggestion.testCode.split('\n').slice(0, 10); + codeLines.forEach((line: string) => { + lines.push(chalk.gray(' │ ') + chalk.white(line)); + }); + if (suggestion.testCode.split('\n').length > 10) { + lines.push(chalk.gray(' │ ... (copy full code below)')); + } + lines.push(chalk.gray(' └─────────────────────────────────────────')); + lines.push(''); + } + } + } + } + + // Test enhancement suggestions + if (enhancements.length > 0) { + lines.push(this.separator()); + lines.push(''); + + if (this.mode === 'markdown') { + lines.push(`### 🔬 Test Enhancement Suggestions (${enhancements.length})`); + } else { + lines.push(chalk.green.bold(`🔬 Test Enhancement Suggestions (${enhancements.length} test files can be improved)`)); + } + lines.push(''); + + for (const suggestion of enhancements) { + const testFile = suggestion.existingTestFile || suggestion.testFilePath; + + if (this.mode === 'markdown') { + lines.push(`**${testFile}**`); + lines.push(`- Source: ${suggestion.forFile}`); + lines.push(`- ${suggestion.description}`); + lines.push(''); + } else { + lines.push(chalk.cyan(` 📊 ${testFile}`)); + lines.push(chalk.gray(` Source: ${suggestion.forFile}`)); + lines.push(chalk.white(` ${suggestion.description}`)); + lines.push(''); + + // Show test code preview for terminal + if (suggestion.testCode && suggestion.testCode.trim()) { + lines.push(chalk.gray(' ┌─────────────────────────────────────────')); + const codeLines = suggestion.testCode.split('\n').slice(0, 15); + codeLines.forEach((line: string) => { + lines.push(chalk.gray(' │ ') + chalk.white(line)); + }); + if (suggestion.testCode.split('\n').length > 15) { + lines.push(chalk.gray(' │ ... (more enhancements available)')); + } + lines.push(chalk.gray(' └─────────────────────────────────────────')); + lines.push(''); + } + } + } + } + + return lines.join('\n'); + } + + /** + * Format project classification section + */ + formatProjectClassification(classification: string | undefined): string { + if (!classification) { + return ''; + } + + const lines: string[] = []; + lines.push(this.separator()); + + if (this.mode === 'markdown') { + lines.push(''); + lines.push(classification); + } else { + // Classification already has chalk formatting from the agent + lines.push(classification); + } + + return lines.join('\n'); + } + + /** + * Format coverage report section + */ + formatCoverageReport(coverageReport: any): string { + if (!coverageReport || !coverageReport.available) { + return ''; + } + + const lines: string[] = []; + lines.push(this.separator()); + lines.push(''); + + if (this.mode === 'markdown') { + lines.push('### 📊 Test Coverage Report'); + lines.push(''); + + if (coverageReport.overallPercentage !== undefined) { + const emoji = coverageReport.overallPercentage >= 80 ? '🟢' : + coverageReport.overallPercentage >= 60 ? '🟡' : '🔴'; + lines.push(`${emoji} Overall Coverage: **${coverageReport.overallPercentage.toFixed(1)}%**`); + } + + if (coverageReport.lineCoverage !== undefined) { + lines.push(`- Lines: ${coverageReport.lineCoverage.toFixed(1)}%`); + } + + if (coverageReport.branchCoverage !== undefined) { + lines.push(`- Branches: ${coverageReport.branchCoverage.toFixed(1)}%`); + } + + if (coverageReport.delta !== undefined) { + const deltaEmoji = coverageReport.delta >= 0 ? '📈' : '📉'; + lines.push(`${deltaEmoji} Coverage Delta: ${coverageReport.delta >= 0 ? '+' : ''}${coverageReport.delta.toFixed(1)}%`); + } + } else { + lines.push(chalk.green.bold('📊 Test Coverage Report')); + lines.push(''); + + if (coverageReport.overallPercentage !== undefined) { + const emoji = coverageReport.overallPercentage >= 80 ? '🟢' : + coverageReport.overallPercentage >= 60 ? '🟡' : '🔴'; + lines.push(chalk.white(` ${emoji} Overall Coverage: ${coverageReport.overallPercentage.toFixed(1)}%`)); + } + + if (coverageReport.lineCoverage !== undefined) { + lines.push(chalk.gray(` Lines: ${coverageReport.lineCoverage.toFixed(1)}%`)); + } + + if (coverageReport.branchCoverage !== undefined) { + lines.push(chalk.gray(` Branches: ${coverageReport.branchCoverage.toFixed(1)}%`)); + } + + if (coverageReport.delta !== undefined) { + const deltaEmoji = coverageReport.delta >= 0 ? '📈' : '📉'; + const deltaColor = coverageReport.delta >= 0 ? chalk.green : chalk.red; + lines.push(deltaColor(` ${deltaEmoji} Coverage Delta: ${coverageReport.delta >= 0 ? '+' : ''}${coverageReport.delta.toFixed(1)}%`)); + } + } + + if (coverageReport.coverageTool) { + lines.push(''); + lines.push(this.dim(`Tool: ${coverageReport.coverageTool}`)); + } + + lines.push(''); + return lines.join('\n'); + } + + /** + * Format DevOps cost estimates section + */ + formatDevOpsCostEstimates(costEstimates: any[]): string { + if (!costEstimates || costEstimates.length === 0) { + return ''; + } + + const lines: string[] = []; + lines.push(this.separator()); + lines.push(''); + + if (this.mode === 'markdown') { + lines.push('## 💰 DevOps Cost Estimates'); + lines.push(''); + + const totalCost = costEstimates.reduce((sum, e) => sum + (e.estimatedMonthlyCost || 0), 0); + lines.push(`**Total Estimated Monthly Cost:** $${totalCost.toFixed(2)}`); + lines.push(''); + + for (const estimate of costEstimates) { + lines.push(`### ${estimate.resourceType || 'Resource'}`); + if (estimate.file) { + lines.push(`File: \`${estimate.file}\``); + } + if (estimate.resourceName) { + lines.push(`Name: **${estimate.resourceName}**`); + } + if (estimate.estimatedMonthlyCost !== undefined) { + lines.push(`Estimated Cost: **$${estimate.estimatedMonthlyCost.toFixed(2)}/month**`); + } + if (estimate.notes) { + lines.push(`Notes: ${estimate.notes}`); + } + lines.push(''); + } + } else { + lines.push(chalk.yellow.bold('💰 DevOps Cost Estimates')); + lines.push(''); + + const totalCost = costEstimates.reduce((sum, e) => sum + (e.estimatedMonthlyCost || 0), 0); + lines.push(chalk.white(` Total Estimated Monthly Cost: $${totalCost.toFixed(2)}`)); + lines.push(''); + + for (const estimate of costEstimates) { + lines.push(chalk.cyan(` ${estimate.resourceType || 'Resource'}`)); + if (estimate.file) { + lines.push(chalk.gray(` File: ${estimate.file}`)); + } + if (estimate.resourceName) { + lines.push(chalk.white(` Name: ${estimate.resourceName}`)); + } + if (estimate.estimatedMonthlyCost !== undefined) { + lines.push(chalk.white(` Estimated Cost: $${estimate.estimatedMonthlyCost.toFixed(2)}/month`)); + } + if (estimate.notes) { + lines.push(chalk.gray(` Notes: ${estimate.notes}`)); + } + lines.push(''); + } + } + + lines.push(''); + return lines.join('\n'); + } + + /** + * Format static analysis section + */ + formatStaticAnalysis(staticAnalysis: any): string { + if (!staticAnalysis) { + return ''; + } + + const lines: string[] = []; + + // Project classification + if (staticAnalysis.projectClassification) { + lines.push(this.formatProjectClassification(staticAnalysis.projectClassification)); + } + + // Test suggestions + if (staticAnalysis.testSuggestions) { + lines.push(this.formatTestSuggestions(staticAnalysis.testSuggestions)); + } + + // DevOps cost estimates + if (staticAnalysis.devOpsCostEstimates) { + lines.push(this.formatDevOpsCostEstimates(staticAnalysis.devOpsCostEstimates)); + } + + // Coverage report + if (staticAnalysis.coverageReport) { + lines.push(this.formatCoverageReport(staticAnalysis.coverageReport)); + } + + return lines.join('\n'); + } +} diff --git a/team-email-short.md b/team-email-short.md new file mode 100644 index 0000000..e2e435d --- /dev/null +++ b/team-email-short.md @@ -0,0 +1,35 @@ +Subject: MCP Server Integration PR Ready for Review + +Hi team, + +I've created a pull request for the MCP Server integration on the upstream repo: + +PR: https://github.com/techdebtgpt/pr-agent/pull/30 + + +What's Done: + +The MCP server lets you run PR Agent directly in Claude Code without API keys. I've thoroughly tested it for backward compatibility with the existing CLI tool and done an extensive refactor to support both modes. + +Installation instructions are in the PR description and README. Refactoring documentation is in the project docs. + + +What's Left: + +Two main things: + +1. Output formatting - Making the MCP output match the CLI format (bit tricky due to the architecture differences) + +2. Multi-tool testing - So far only tested with Claude. Need to verify with Cursor and other AI tools. + + +Next Steps: + +Feel free to review when you have time. Happy to answer any questions or walk through anything in more detail. + +Thanks! + + +Links: +• Upstream PR: https://github.com/techdebtgpt/pr-agent/pull/30 +• Fork PR: https://github.com/dzdimov/PeeR-Agent/pull/18 diff --git a/team-email.md b/team-email.md new file mode 100644 index 0000000..a74f1fe --- /dev/null +++ b/team-email.md @@ -0,0 +1,93 @@ +Subject: 🚀 MCP Server Integration PR Ready for Review - Backward Compatible with CLI + +Hi Team, + +I'm excited to share that I've created a pull request for the **MCP Server Integration** on the upstream repository: + +**Pull Request:** https://github.com/techdebtgpt/pr-agent/pull/30 + +## 📋 What's New + +This PR introduces a comprehensive **Model Context Protocol (MCP) server** that enables AI-powered PR analysis directly within Claude Code, Cursor, and other MCP-compatible editors—**without requiring API keys**. + +### ✅ Key Features +- **LLM-Agnostic Architecture**: Works by generating structured prompts for the calling LLM to execute +- **Static Analysis**: Provides immediate value (project classification, test suggestions, DevOps cost estimates, coverage reports) +- **Peer Review Integration**: Full Jira ticket validation, AC checking, and quality assessment +- **Auto-Start Dashboard**: Analysis results automatically saved and dashboard launched at http://localhost:3000 + +## 🧪 Testing & Compatibility + +I have **thoroughly tested** this implementation for **backward compatibility with the CLI tool**. The extensive refactoring maintains all existing CLI functionality while adding the new MCP server capabilities. + +Testing was performed on: +- Multiple repository types (todo-ai-agents, peer-agent) +- Various branch configurations +- Peer review scenarios with Jira integration +- Dashboard integration and data persistence + +## 📖 Documentation Included + +I've provided comprehensive documentation to help the team get started: + +1. **Installation Instructions**: Detailed step-by-step guide in the PR description + - Package installation (npm/yarn) + - MCP server configuration for Claude Code + - Repository configuration setup + - No API keys needed! + +2. **README Sections**: Updated project README with MCP server usage + +3. **Refactoring Documentation**: Technical documentation on how the refactor was carried out is included in the project documentation, covering: + - Architecture decisions (PROMPT_ONLY vs EXECUTE modes) + - Type system updates for multi-mode support + - Integration with existing peer review system + - Backward compatibility approach + +## 🚧 Remaining Work + +There are **two main areas** that still need attention: + +### 1. Output Format Consistency +The MCP server output format needs to be standardized to match the CLI output format. Currently: +- MCP returns structured prompts + static analysis in Markdown +- CLI returns unified formatted output with sections + +This is somewhat **challenging due to the nature of the MCP architecture** (prompt-only mode where the calling LLM executes prompts vs. CLI's direct execution mode), but the goal is to provide the same visual experience regardless of entry point. + +### 2. Multi-Tool Testing +So far, I have **only tested with Claude** (Anthropic). We need to validate that the MCP server works correctly with: +- **Cursor** (various LLM providers) +- **Windsurf** (if team uses it) +- **Other MCP-compatible clients** + +Different underlying AI tools may handle prompt execution differently, so we should ensure consistent behavior across platforms. + +## 🔍 Review Request + +Please review the PR when you have a chance. Key areas to focus on: +- Installation instructions clarity +- Architecture decisions (PROMPT_ONLY mode) +- Backward compatibility verification +- Documentation completeness + +The implementation is feature-complete and working, with the output formatting polish being the main outstanding task. + +## 🚀 Next Steps After Merge + +1. Publish updated package to npm +2. Team rollout with installation instructions +3. Collect feedback on MCP integration +4. Address output formatting consistency +5. Test with additional AI tools beyond Claude + +Looking forward to your feedback! + +Best regards, +[Your Name] + +--- + +**Pull Requests:** +- Upstream: https://github.com/techdebtgpt/pr-agent/pull/30 +- Fork: https://github.com/dzdimov/PeeR-Agent/pull/18 diff --git a/tests/mcp/README.md b/tests/mcp/README.md new file mode 100644 index 0000000..bc8d084 --- /dev/null +++ b/tests/mcp/README.md @@ -0,0 +1,180 @@ +# MCP Server Test Suite + +Comprehensive unit and integration tests for the MCP (Model Context Protocol) server implementation following best practices from the MCP testing ecosystem. + +## Testing Approach + +Based on research of [MCP testing best practices](https://modelcontextprotocol.info/docs/best-practices/), [unit testing guides](https://milvus.io/ai-quick-reference/how-do-i-write-unit-tests-for-model-context-protocol-mcp-tools-and-resources), and the [MCP testing framework](https://github.com/haakco/mcp-testing-framework). + +### Test Categories + +#### 1. Unit Tests +Tests for individual services and components in isolation: +- **GitService** - Git command execution and parsing +- **TicketExtractorService** - Ticket reference extraction from PR metadata +- **FormatterService** - Output formatting for MCP responses +- **DevOps Cost Estimator** - Infrastructure cost estimation for IaC files + +#### 2. Integration Tests +Tests for complete workflows and MCP tool execution: +- **AnalyzeTool** - Full analysis workflow with mocked git commands +- **SaveResultsTool** - Database operations and result persistence +- **DashboardTool** - Dashboard service integration +- **MCP Server** - End-to-end MCP protocol compliance + +## Test Files + +``` +tests/mcp/ +├── services/ +│ ├── git.service.test.ts # Unit tests for GitService +│ ├── ticket-extractor.service.test.ts # Unit tests for TicketExtractorService +│ └── formatter.service.test.ts # Unit tests for FormatterService +├── tools/ +│ ├── analyze-tool.integration.test.ts # Integration tests for AnalyzeTool +│ └── save-results-tool.integration.test.ts # Integration tests for SaveResultsTool +└── server.integration.test.ts # MCP server protocol tests + +tests/tools/ +└── devops-cost-estimator.test.ts # Unit tests for DevOps cost estimation +``` + +## Key Testing Patterns + +### 1. Mocking External Dependencies + +```typescript +// Mock git commands +jest.mock('child_process'); +(childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git diff')) { + return Buffer.from('diff content'); + } + return Buffer.from(''); +}); +``` + +### 2. Testing MCP Tool Response Format + +```typescript +// Verify MCP response structure +expect(result).toHaveProperty('content'); +expect(Array.isArray(result.content)).toBe(true); +expect(result.content[0]).toHaveProperty('type'); +expect(result.content[0]).toHaveProperty('text'); +expect(result.content[0].type).toBe('text'); +``` + +### 3. Testing PROMPT_ONLY Mode + +```typescript +// Verify prompts are returned without LLM execution +const result = await analyzeTool.execute({ branch: 'main' }); +expect(result.content[0].text).toContain('LLM Analysis Workflow'); +expect(result.content[0].text).toContain('prompts sequentially'); +expect(result.content[0].text).not.toContain('Analysis Complete'); +``` + +### 4. Testing Deterministic Analysis + +```typescript +// DevOps cost estimation should run without LLM +const result = await analyzeTool.execute({ branch: 'main' }); +expect(result.content[0].text).toContain('DevOps Cost Estimates'); +expect(result.content[0].text).toContain('Static Analysis Results'); +``` + +## Running Tests + +```bash +# Run all tests +npm test + +# Run MCP tests only +npm test -- tests/mcp + +# Run specific test file +npm test -- tests/mcp/services/git.service.test.ts + +# Run with coverage +npm test -- --coverage + +# Watch mode +npm test -- --watch +``` + +## Test Coverage Goals + +- **Services**: ≥80% line coverage +- **Tools**: ≥75% line coverage (integration tests) +- **Critical paths**: 100% coverage (error handling, MCP response format) + +## Testing Principles + +1. **Isolation**: Unit tests mock all external dependencies +2. **Integration**: Integration tests verify real component interactions +3. **Fast Execution**: Tests run quickly with minimal I/O +4. **Reliable**: Tests are deterministic and don't depend on external services +5. **MCP Compliance**: Verify proper MCP protocol response formats + +## Mocking Strategy + +### External Services +- **Git commands**: Mocked via `child_process.execSync` +- **File system**: Temporary directories for test isolation +- **Database**: In-memory SQLite or temp files +- **LLM calls**: Not executed in MCP server (PROMPT_ONLY mode) + +### Internal Services +- **DashboardService**: Mocked in tool tests +- **Config loader**: Mocked to return test configurations +- **Branch resolver**: Mocked to avoid GitHub API calls + +## Common Test Utilities + +### Temporary Test Directories + +```typescript +beforeEach(() => { + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pr-agent-test-')); +}); + +afterEach(() => { + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true, force: true }); + } +}); +``` + +### Mock Git Repository + +```typescript +(childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git rev-parse --abbrev-ref HEAD')) { + return Buffer.from('feature/test-branch'); + } + if (command.includes('git remote get-url origin')) { + return Buffer.from('https://github.com/owner/repo.git'); + } + return Buffer.from(''); +}); +``` + +## References + +- [MCP Best Practices](https://modelcontextprotocol.info/docs/best-practices/) +- [MCP Unit Testing Guide](https://milvus.io/ai-quick-reference/how-do-i-write-unit-tests-for-model-context-protocol-mcp-tools-and-resources) +- [MCP Testing Framework](https://github.com/haakco/mcp-testing-framework) +- [TypeScript MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) + +## Contributing + +When adding new MCP server features: + +1. Add unit tests for new services +2. Add integration tests for new tools +3. Verify MCP protocol compliance +4. Test error handling paths +5. Update this README with new patterns diff --git a/tests/mcp/server.integration.test.ts b/tests/mcp/server.integration.test.ts new file mode 100644 index 0000000..dcdd257 --- /dev/null +++ b/tests/mcp/server.integration.test.ts @@ -0,0 +1,339 @@ +/** + * Integration tests for MCP Server + * Tests complete MCP protocol interaction and tool execution + */ + +import { describe, it, expect, jest, beforeEach } from '@jest/globals'; +import * as childProcess from 'child_process'; + +// Mock dependencies before imports +jest.mock('child_process'); +jest.mock('../../src/cli/utils/config-loader.js'); + +describe('MCP Server Integration Tests', () => { + beforeEach(() => { + // Setup default git command mocks + (childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git rev-parse --abbrev-ref HEAD')) { + return Buffer.from('main'); + } + if (command.includes('git log -1 --pretty=%s')) { + return Buffer.from('test commit'); + } + if (command.includes('git remote get-url origin')) { + return Buffer.from('https://github.com/test/repo.git'); + } + if (command.includes('git diff')) { + return Buffer.from('diff --git a/file.ts b/file.ts\n+test'); + } + return Buffer.from(''); + }); + + jest.clearAllMocks(); + }); + + describe('Tool Integration', () => { + it('should execute analyze tool end-to-end', async () => { + const { AnalyzeTool } = await import('../../src/mcp/tools/analyze-tool.js'); + const { DashboardService } = await import('../../src/mcp/services/dashboard.service.js'); + + const mockDashboard = { + startInBackground: jest.fn(() => Promise.resolve()), + } as any; + + const tool = new AnalyzeTool(mockDashboard); + + const result = await tool.execute({ + branch: 'main', + staged: false, + verbose: false, + }); + + expect(result.content[0].text).toContain('Static Analysis Results'); + expect(result.content[0].text).toContain('LLM Analysis Workflow'); + }); + + it('should execute saveAnalysisResults tool end-to-end', async () => { + const { SaveResultsTool } = await import('../../src/mcp/tools/save-results-tool.js'); + + const tool = new SaveResultsTool(); + + // Use temp database + const tempDbPath = require('path').join(require('os').tmpdir(), `test-${Date.now()}.db`); + process.env.PR_AGENT_DB_PATH = tempDbPath; + + try { + const result = await tool.execute({ + title: 'Test PR', + repoOwner: 'test', + repoName: 'repo', + complexity: 2, + risksCount: 1, + risks: ['Risk'], + recommendations: ['Rec'], + }); + + expect(result.content[0].text).toContain('Analysis results saved'); + } finally { + delete process.env.PR_AGENT_DB_PATH; + try { + require('fs').unlinkSync(tempDbPath); + } catch { + // Ignore + } + } + }); + + it('should execute dashboard tool end-to-end', async () => { + const { DashboardTool } = await import('../../src/mcp/tools/dashboard-tool.js'); + const { DashboardService } = await import('../../src/mcp/services/dashboard.service.js'); + + const mockDashboard = { + start: jest.fn(() => Promise.resolve()), + } as any; + + const tool = new DashboardTool(mockDashboard); + + const result = await tool.execute({ port: 3000 }, __dirname); + + expect(result.content[0].text).toContain('Dashboard'); + }); + }); + + describe('Service Integration', () => { + it('should integrate GitService correctly', async () => { + const { GitService } = await import('../../src/mcp/services/git.service.js'); + + (childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git diff')) { + return Buffer.from('test diff'); + } + return Buffer.from('test'); + }); + + try { + const diff = GitService.getGitDiff('git diff main'); + expect(diff).toBe('test diff'); + } catch (error) { + // Expected to fail in PROMPT_ONLY mode + expect(error).toBeDefined(); + } + }); + + it('should integrate TicketExtractorService correctly', async () => { + const { TicketExtractorService } = await import( + '../../src/mcp/services/ticket-extractor.service.js' + ); + + const refs = TicketExtractorService.extractTicketReferences( + 'TODO-123 Title', + 'feature/TODO-123', + [], + 'TODO' + ); + + expect(refs.length).toBeGreaterThan(0); + expect(refs.some((r) => r.key === 'TODO-123')).toBe(true); + }); + + it('should integrate FormatterService correctly', async () => { + const { FormatterService } = await import('../../src/mcp/services/formatter.service.js'); + + const output = FormatterService.formatAnalysisOutput({ + verbose: false, + peerReviewEnabled: false, + allPrompts: [], + repoInfo: { owner: 'test', name: 'repo' }, + currentBranch: 'main', + baseBranch: 'origin/main', + title: 'Test', + }); + + expect(output).toContain('Static Analysis Results'); + expect(output).toContain('DevOps Cost Estimates'); + }); + }); + + describe('Error Handling', () => { + it('should handle git command failures gracefully', async () => { + (childProcess.execSync as jest.Mock).mockImplementation(() => { + throw new Error('Git error'); + }); + + const { AnalyzeTool } = await import('../../src/mcp/tools/analyze-tool.js'); + const { DashboardService } = await import('../../src/mcp/services/dashboard.service.js'); + + const mockDashboard = { + startInBackground: jest.fn(() => Promise.resolve()), + } as any; + + const tool = new AnalyzeTool(mockDashboard); + + const result = await tool.execute({ branch: 'main' }); + + expect(result.content[0].text).toContain('Analysis failed'); + }); + + it('should handle missing configuration gracefully', async () => { + const configLoader = await import('../../src/cli/utils/config-loader.js'); + (configLoader.loadUserConfig as any) = jest.fn(() => + Promise.reject(new Error('Config not found')) + ); + + const { AnalyzeTool } = await import('../../src/mcp/tools/analyze-tool.js'); + const { DashboardService } = await import('../../src/mcp/services/dashboard.service.js'); + + const mockDashboard = { + startInBackground: jest.fn(() => Promise.resolve()), + } as any; + + const tool = new AnalyzeTool(mockDashboard); + + // Should still work without config + const result = await tool.execute({ branch: 'main' }); + + expect(result.content).toBeDefined(); + }); + + it('should handle dashboard startup failures', async () => { + const { AnalyzeTool } = await import('../../src/mcp/tools/analyze-tool.js'); + + const mockDashboard = { + startInBackground: jest.fn(() => Promise.reject(new Error('Port in use'))), + } as any; + + const tool = new AnalyzeTool(mockDashboard); + + // Should complete analysis even if dashboard fails + const result = await tool.execute({ branch: 'main' }); + + expect(result.content[0].text).toContain('Static Analysis Results'); + }); + }); + + describe('PROMPT_ONLY Mode', () => { + it('should return prompts without executing LLM', async () => { + const { AnalyzeTool } = await import('../../src/mcp/tools/analyze-tool.js'); + const { DashboardService } = await import('../../src/mcp/services/dashboard.service.js'); + + const mockDashboard = { + startInBackground: jest.fn(() => Promise.resolve()), + } as any; + + const tool = new AnalyzeTool(mockDashboard); + + const result = await tool.execute({ + branch: 'main', + verbose: true, + }); + + const output = result.content[0].text; + + // Should contain prompt steps + expect(output).toContain('Step 1:'); + expect(output).toContain('Prompt:'); + expect(output).toContain('Execute the following'); + expect(output).toContain('prompts sequentially'); + + // Should NOT contain LLM execution results (those come from calling LLM) + expect(output).not.toContain('Analysis Complete'); + }); + + it('should include static analysis in PROMPT_ONLY mode', async () => { + const { AnalyzeTool } = await import('../../src/mcp/tools/analyze-tool.js'); + const { DashboardService } = await import('../../src/mcp/services/dashboard.service.js'); + + const mockDashboard = { + startInBackground: jest.fn(() => Promise.resolve()), + } as any; + + const tool = new AnalyzeTool(mockDashboard); + + const result = await tool.execute({ branch: 'main' }); + + const output = result.content[0].text; + + // Static analysis should run immediately + expect(output).toContain('Static Analysis Results'); + }); + + it('should include DevOps cost estimates in PROMPT_ONLY mode', async () => { + // Mock Terraform file in diff + (childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git diff')) { + return Buffer.from(`diff --git a/main.tf b/main.tf ++resource "aws_instance" "web" { ++ instance_type = "t3.medium" ++}`); + } + if (command.includes('git rev-parse --abbrev-ref HEAD')) { + return Buffer.from('feature/infra'); + } + return Buffer.from('test'); + }); + + const { AnalyzeTool } = await import('../../src/mcp/tools/analyze-tool.js'); + const { DashboardService } = await import('../../src/mcp/services/dashboard.service.js'); + + const mockDashboard = { + startInBackground: jest.fn(() => Promise.resolve()), + } as any; + + const tool = new AnalyzeTool(mockDashboard); + + const result = await tool.execute({ branch: 'main', verbose: true }); + + const output = result.content[0].text; + + // DevOps cost analysis should run deterministically + expect(output).toContain('DevOps Cost Estimates'); + }); + }); + + describe('Workflow Integration', () => { + it('should complete full analyze -> save workflow', async () => { + const { AnalyzeTool } = await import('../../src/mcp/tools/analyze-tool.js'); + const { SaveResultsTool } = await import('../../src/mcp/tools/save-results-tool.js'); + const { DashboardService } = await import('../../src/mcp/services/dashboard.service.js'); + + const mockDashboard = { + startInBackground: jest.fn(() => Promise.resolve()), + } as any; + + // Step 1: Analyze + const analyzeTool = new AnalyzeTool(mockDashboard); + const analyzeResult = await analyzeTool.execute({ branch: 'main' }); + + expect(analyzeResult.content[0].text).toContain('prompts sequentially'); + + // Step 2: Save (after LLM execution in real scenario) + const tempDbPath = require('path').join(require('os').tmpdir(), `test-${Date.now()}.db`); + process.env.PR_AGENT_DB_PATH = tempDbPath; + + try { + const saveTool = new SaveResultsTool(); + const saveResult = await saveTool.execute({ + title: 'Test PR', + repoOwner: 'test', + repoName: 'repo', + complexity: 3, + risksCount: 2, + risks: ['Risk 1', 'Risk 2'], + recommendations: ['Rec 1', 'Rec 2'], + }); + + expect(saveResult.content[0].text).toContain('Analysis results saved'); + } finally { + delete process.env.PR_AGENT_DB_PATH; + try { + require('fs').unlinkSync(tempDbPath); + } catch { + // Ignore + } + } + }); + }); +}); diff --git a/tests/mcp/services/formatter.service.test.ts b/tests/mcp/services/formatter.service.test.ts new file mode 100644 index 0000000..d2bf500 --- /dev/null +++ b/tests/mcp/services/formatter.service.test.ts @@ -0,0 +1,247 @@ +/** + * Unit tests for FormatterService + * Tests MCP output formatting + */ + +import { describe, it, expect } from '@jest/globals'; +import { FormatterService } from '../../../src/mcp/services/formatter.service.js'; +import type { AnalysisOutputOptions } from '../../../src/mcp/types.js'; + +describe('FormatterService', () => { + describe('formatAnalysisOutput', () => { + const baseOptions: AnalysisOutputOptions = { + verbose: false, + peerReviewEnabled: false, + allPrompts: [], + repoInfo: { owner: 'test-owner', name: 'test-repo' }, + currentBranch: 'feature/test', + baseBranch: 'main', + title: 'Test PR', + }; + + it('should format basic analysis output', () => { + const output = FormatterService.formatAnalysisOutput(baseOptions); + + expect(output).toContain('Static Analysis Results'); + expect(output).toContain('DevOps Cost Estimates'); + expect(output).toContain('LLM Analysis Workflow'); + expect(output).toContain('Next Steps'); + }); + + it('should include header in verbose mode', () => { + const options: AnalysisOutputOptions = { + ...baseOptions, + verbose: true, + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('PR Agent Analysis'); + expect(output).toContain('Repository: test-owner/test-repo'); + expect(output).toContain('Branch: feature/test → main'); + expect(output).toContain('PR Title: Test PR'); + }); + + it('should format DevOps cost estimates when present', () => { + const options: AnalysisOutputOptions = { + ...baseOptions, + devOpsCostEstimates: [ + { + resource: 'test-resource', + resourceType: 'ec2', + estimatedNewCost: 34.5, + confidence: 'high', + details: 'Estimated $30-40/month', + }, + ], + totalDevOpsCost: 34.5, + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('Total Estimated Monthly Cost: $34.50'); + expect(output).toContain('ec2'); + expect(output).toContain('$34.50/month'); + expect(output).toContain('🟢'); // High confidence emoji + }); + + it('should show "No DevOps infrastructure changes" when no estimates', () => { + const output = FormatterService.formatAnalysisOutput(baseOptions); + + expect(output).toContain('No DevOps infrastructure changes detected'); + }); + + it('should format static analysis when present', () => { + const options: AnalysisOutputOptions = { + ...baseOptions, + staticAnalysis: { + testSuggestions: [ + { + file: 'test.ts', + suggestions: ['Test case 1', 'Test case 2'], + }, + ], + coverageReport: { + totalCoverage: 85, + lineCoverage: 90, + branchCoverage: 80, + }, + }, + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('Static Analysis Results'); + }); + + it('should format project classification when present', () => { + const options: AnalysisOutputOptions = { + ...baseOptions, + projectClassification: { + type: 'business-logic', + confidence: 95, + indicators: ['React components', 'API calls'], + }, + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('Static Analysis Results'); + }); + + it('should include prompts in workflow section', () => { + const options: AnalysisOutputOptions = { + ...baseOptions, + allPrompts: [ + { + step: 'fileAnalysis', + prompt: 'Analyze these files...', + instructions: 'Provide detailed analysis', + }, + { + step: 'riskDetection', + prompt: 'Detect risks...', + instructions: 'Identify security issues', + }, + ], + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('Execute the following 2 prompts sequentially'); + expect(output).toContain('Step 1: fileAnalysis'); + expect(output).toContain('Step 2: riskDetection'); + }); + + it('should truncate long prompts in normal mode', () => { + const longPrompt = 'A'.repeat(3000); + const options: AnalysisOutputOptions = { + ...baseOptions, + verbose: false, + allPrompts: [ + { + step: 'fileAnalysis', + prompt: longPrompt, + instructions: 'Test', + }, + ], + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('(truncated for display)'); + }); + + it('should show longer prompts in verbose mode', () => { + const longPrompt = 'A'.repeat(8000); + const options: AnalysisOutputOptions = { + ...baseOptions, + verbose: true, + allPrompts: [ + { + step: 'fileAnalysis', + prompt: longPrompt, + instructions: 'Test', + }, + ], + }; + + const output = FormatterService.formatAnalysisOutput(options); + + // In verbose mode, limit is higher but still truncates very long prompts + expect(output.length).toBeGreaterThan(0); + }); + + it('should show peer review error when present', () => { + const options: AnalysisOutputOptions = { + ...baseOptions, + peerReviewEnabled: true, + peerReviewError: 'Jira connection failed', + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('Peer Review Error'); + expect(output).toContain('Jira connection failed'); + expect(output).toContain('Possible causes:'); + }); + + it('should include dashboard URL in verbose mode', () => { + const options: AnalysisOutputOptions = { + ...baseOptions, + verbose: true, + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('Dashboard: http://localhost:3000'); + }); + + it('should include next steps instructions', () => { + const options: AnalysisOutputOptions = { + ...baseOptions, + allPrompts: [ + { step: 'fileAnalysis', prompt: 'test', instructions: 'test' }, + ], + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('Next Steps'); + expect(output).toContain('Execute the following 1 prompts sequentially'); + }); + + it('should show confidence indicators for cost estimates', () => { + const options: AnalysisOutputOptions = { + ...baseOptions, + devOpsCostEstimates: [ + { + resource: 'high-conf', + resourceType: 'alb', + estimatedNewCost: 22, + confidence: 'high', + }, + { + resource: 'medium-conf', + resourceType: 'ec2', + estimatedNewCost: 34, + confidence: 'medium', + }, + { + resource: 'low-conf', + resourceType: 'lambda', + estimatedNewCost: 0.4, + confidence: 'low', + }, + ], + totalDevOpsCost: 56.4, + }; + + const output = FormatterService.formatAnalysisOutput(options); + + expect(output).toContain('🟢'); // high confidence + expect(output).toContain('🟡'); // medium confidence + expect(output).toContain('🔴'); // low confidence + }); + }); +}); diff --git a/tests/mcp/services/git.service.test.ts b/tests/mcp/services/git.service.test.ts new file mode 100644 index 0000000..eec1672 --- /dev/null +++ b/tests/mcp/services/git.service.test.ts @@ -0,0 +1,180 @@ +/** + * Unit tests for GitService + * Tests git command execution and output parsing + */ + +import { describe, it, expect, jest, beforeEach } from '@jest/globals'; +import { GitService } from '../../../src/mcp/services/git.service.js'; +import * as childProcess from 'child_process'; + +// Mock child_process +jest.mock('child_process'); + +describe('GitService', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('getGitDiff', () => { + it('should execute git diff command and return output', () => { + const mockDiff = 'diff --git a/file.ts b/file.ts\n+added line'; + (childProcess.execSync as jest.Mock).mockReturnValue(Buffer.from(mockDiff)); + + const result = GitService.getGitDiff('git diff main', { cwd: '/test' }); + + expect(result).toBe(mockDiff); + expect(childProcess.execSync).toHaveBeenCalledWith( + 'git diff main', + expect.objectContaining({ cwd: '/test' }) + ); + }); + + it('should return empty string when git command fails', () => { + (childProcess.execSync as jest.Mock).mockImplementation(() => { + throw new Error('Git command failed'); + }); + + const result = GitService.getGitDiff('git diff main'); + + expect(result).toBe(''); + }); + + it('should trim whitespace from diff output', () => { + const mockDiff = ' \n diff content \n '; + (childProcess.execSync as jest.Mock).mockReturnValue(Buffer.from(mockDiff)); + + const result = GitService.getGitDiff('git diff main'); + + expect(result).toBe('diff content'); + }); + }); + + describe('getCurrentBranch', () => { + it('should return current branch name', () => { + (childProcess.execSync as jest.Mock).mockReturnValue(Buffer.from('feature/test-branch\n')); + + const result = GitService.getCurrentBranch('/test'); + + expect(result).toBe('feature/test-branch'); + expect(childProcess.execSync).toHaveBeenCalledWith( + 'git rev-parse --abbrev-ref HEAD', + expect.objectContaining({ cwd: '/test' }) + ); + }); + + it('should return "unknown" when git command fails', () => { + (childProcess.execSync as jest.Mock).mockImplementation(() => { + throw new Error('Not a git repository'); + }); + + const result = GitService.getCurrentBranch('/test'); + + expect(result).toBe('unknown'); + }); + }); + + describe('getPRTitle', () => { + it('should return latest commit message as PR title', () => { + const commitMessage = 'feat: Add new feature'; + (childProcess.execSync as jest.Mock).mockReturnValue(Buffer.from(commitMessage)); + + const result = GitService.getPRTitle('/test'); + + expect(result).toBe(commitMessage); + expect(childProcess.execSync).toHaveBeenCalledWith( + 'git log -1 --pretty=%B', + expect.objectContaining({ cwd: '/test' }) + ); + }); + + it('should return "Untitled PR" when git command fails', () => { + (childProcess.execSync as jest.Mock).mockImplementation(() => { + throw new Error('No commits'); + }); + + const result = GitService.getPRTitle('/test'); + + expect(result).toBe('Untitled PR'); + }); + }); + + describe('getCommitMessages', () => { + it('should return array of commit messages', () => { + const commits = 'commit1\ncommit2\ncommit3'; + (childProcess.execSync as jest.Mock).mockReturnValue(Buffer.from(commits)); + + const result = GitService.getCommitMessages('/test'); + + expect(result).toEqual(['commit1', 'commit2', 'commit3']); + }); + + it('should filter empty lines', () => { + const commits = 'commit1\n\n\ncommit2\n\ncommit3'; + (childProcess.execSync as jest.Mock).mockReturnValue(Buffer.from(commits)); + + const result = GitService.getCommitMessages('/test'); + + expect(result).toEqual(['commit1', 'commit2', 'commit3']); + }); + + it('should return empty array when git command fails', () => { + (childProcess.execSync as jest.Mock).mockImplementation(() => { + throw new Error('Git error'); + }); + + const result = GitService.getCommitMessages('/test'); + + expect(result).toEqual([]); + }); + }); + + describe('getRepoInfo', () => { + it('should parse GitHub HTTPS remote URL', () => { + const remoteUrl = 'https://github.com/owner/repo.git'; + (childProcess.execSync as jest.Mock).mockReturnValue(Buffer.from(remoteUrl)); + + const result = GitService.getRepoInfo('/test'); + + expect(result).toEqual({ + owner: 'owner', + name: 'repo', + }); + }); + + it('should parse GitHub SSH remote URL', () => { + const remoteUrl = 'git@github.com:owner/repo.git'; + (childProcess.execSync as jest.Mock).mockReturnValue(Buffer.from(remoteUrl)); + + const result = GitService.getRepoInfo('/test'); + + expect(result).toEqual({ + owner: 'owner', + name: 'repo', + }); + }); + + it('should return default values for invalid remote URL', () => { + (childProcess.execSync as jest.Mock).mockReturnValue(Buffer.from('invalid-url')); + + const result = GitService.getRepoInfo('/test'); + + expect(result).toEqual({ + owner: 'local', + name: 'unknown', + }); + }); + + it('should return default values when git command fails', () => { + (childProcess.execSync as jest.Mock).mockImplementation(() => { + throw new Error('No remote'); + }); + + const result = GitService.getRepoInfo('/test'); + + expect(result).toEqual({ + owner: 'local', + name: 'unknown', + }); + }); + }); +}); diff --git a/tests/mcp/services/ticket-extractor.service.test.ts b/tests/mcp/services/ticket-extractor.service.test.ts new file mode 100644 index 0000000..1a0c0d4 --- /dev/null +++ b/tests/mcp/services/ticket-extractor.service.test.ts @@ -0,0 +1,151 @@ +/** + * Unit tests for TicketExtractorService + * Tests ticket reference extraction from PR metadata + */ + +import { describe, it, expect } from '@jest/globals'; +import { TicketExtractorService } from '../../../src/mcp/services/ticket-extractor.service.js'; + +describe('TicketExtractorService', () => { + describe('extractTicketReferences', () => { + it('should extract ticket from branch name', () => { + const refs = TicketExtractorService.extractTicketReferences( + 'Fix bug', + 'feature/TODO-123-add-feature', + [], + 'TODO' + ); + + expect(refs).toEqual([ + { + key: 'TODO-123', + source: 'branch', + confidence: 90, + }, + ]); + }); + + it('should extract ticket from PR title', () => { + const refs = TicketExtractorService.extractTicketReferences( + '[TODO-456] Fix critical bug', + 'feature/some-branch', + [], + 'TODO' + ); + + expect(refs).toContainEqual( + expect.objectContaining({ + key: 'TODO-456', + source: 'title', + }) + ); + }); + + it('should extract ticket from commit messages', () => { + const commits = [ + 'feat: Implement feature for PROJ-789', + 'fix: Address TODO-123 issue', + ]; + + const refs = TicketExtractorService.extractTicketReferences( + 'Update code', + 'feature/update', + commits, + 'TODO' + ); + + expect(refs).toContainEqual( + expect.objectContaining({ + key: 'TODO-123', + source: 'commit', + }) + ); + }); + + it('should deduplicate ticket references', () => { + const commits = ['TODO-123: Update', 'Fix TODO-123 bug']; + + const refs = TicketExtractorService.extractTicketReferences( + '[TODO-123] Title', + 'feature/TODO-123-branch', + commits, + 'TODO' + ); + + const todo123Refs = refs.filter((r) => r.key === 'TODO-123'); + // Should have refs from title, branch, and commit but deduplicated + expect(todo123Refs.length).toBeGreaterThan(0); + }); + + it('should return empty array when no tickets found', () => { + const refs = TicketExtractorService.extractTicketReferences( + 'Simple PR', + 'feature/no-ticket', + ['No ticket commit'], + 'TODO' + ); + + expect(refs).toEqual([]); + }); + + it('should handle multiple ticket formats', () => { + const refs = TicketExtractorService.extractTicketReferences( + 'Fix TODO-123 and PROJ-456', + 'feature/update', + [], + 'TODO' + ); + + expect(refs.length).toBeGreaterThan(0); + expect(refs.some((r) => r.key === 'TODO-123')).toBe(true); + }); + + it('should prioritize defaultProject tickets', () => { + const refs = TicketExtractorService.extractTicketReferences( + 'Fix TODO-123', + 'feature/branch', + [], + 'TODO' + ); + + const todo123 = refs.find((r) => r.key === 'TODO-123'); + expect(todo123).toBeDefined(); + expect(todo123?.confidence).toBeGreaterThan(0.7); + }); + + it('should not match lowercase ticket keys', () => { + // Ticket pattern only matches uppercase (e.g., TODO-123, not todo-123) + const refs = TicketExtractorService.extractTicketReferences( + 'Fix todo-123 bug', + 'feature/todo-456', + [], + 'TODO' + ); + + // Lowercase tickets should not be extracted + expect(refs.length).toBe(0); + }); + + it('should extract from complex branch names', () => { + const refs = TicketExtractorService.extractTicketReferences( + 'Feature', + 'feature/TODO-789-implement-complex-feature-with-details', + [], + 'TODO' + ); + + expect(refs).toContainEqual( + expect.objectContaining({ + key: 'TODO-789', + source: 'branch', + }) + ); + }); + + it('should handle empty inputs gracefully', () => { + const refs = TicketExtractorService.extractTicketReferences('', '', [], ''); + + expect(refs).toEqual([]); + }); + }); +}); diff --git a/tests/mcp/tools/analyze-tool.integration.test.ts b/tests/mcp/tools/analyze-tool.integration.test.ts new file mode 100644 index 0000000..92a4dd5 --- /dev/null +++ b/tests/mcp/tools/analyze-tool.integration.test.ts @@ -0,0 +1,333 @@ +/** + * Integration tests for AnalyzeTool + * Tests the complete analysis workflow including MCP tool execution + */ + +import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals'; +import { AnalyzeTool } from '../../../src/mcp/tools/analyze-tool.js'; +import { DashboardService } from '../../../src/mcp/services/dashboard.service.js'; +import * as childProcess from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; + +// Mock dependencies +jest.mock('child_process'); +jest.mock('../../../src/cli/utils/config-loader.js'); +jest.mock('../../../src/utils/branch-resolver.js'); + +describe('AnalyzeTool Integration Tests', () => { + let analyzeTool: AnalyzeTool; + let mockDashboardService: jest.Mocked; + let tempDir: string; + + beforeEach(async () => { + // Create temp directory for test + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pr-agent-analyze-test-')); + + // Mock config loader + const configLoader = await import('../../../src/cli/utils/config-loader.js'); + (configLoader.loadUserConfig as any) = jest.fn(() => Promise.resolve({})); + + // Mock branch resolver + const branchResolver = await import('../../../src/utils/branch-resolver.js'); + (branchResolver.resolveDefaultBranch as any) = jest.fn(() => Promise.resolve({ branch: 'origin/main' })); + + // Mock DashboardService + mockDashboardService = { + startInBackground: jest.fn(() => Promise.resolve()), + } as any; + + analyzeTool = new AnalyzeTool(mockDashboardService); + + // Setup default git command mocks + (childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git rev-parse --abbrev-ref HEAD')) { + return Buffer.from('feature/test-branch'); + } + if (command.includes('git log -1 --pretty=%s')) { + return Buffer.from('feat: Add new feature'); + } + if (command.includes('git remote get-url origin')) { + return Buffer.from('https://github.com/test-owner/test-repo.git'); + } + if (command.includes('git log')) { + return Buffer.from('feat: commit 1\nfix: commit 2'); + } + if (command.includes('git diff')) { + return Buffer.from('diff --git a/file.ts b/file.ts\n+new line'); + } + return Buffer.from(''); + }); + + jest.clearAllMocks(); + }); + + afterEach(() => { + try { + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true, force: true }); + } + } catch { + // Ignore cleanup errors + } + }); + + describe('execute', () => { + it('should execute full analysis workflow successfully', async () => { + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + verbose: false, + }); + + expect(result.content).toBeDefined(); + expect(result.content.length).toBeGreaterThan(0); + expect(result.content[0].type).toBe('text'); + expect(result.content[0].text).toContain('Static Analysis Results'); + }); + + it('should return error when no changes detected', async () => { + // Mock git diff to return empty + (childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git diff')) { + return Buffer.from(''); + } + if (command.includes('git rev-parse --abbrev-ref HEAD')) { + return Buffer.from('feature/test-branch'); + } + return Buffer.from('test'); + }); + + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + }); + + expect(result.content[0].text).toContain('No changes detected'); + }); + + it('should analyze staged changes when staged flag is true', async () => { + (childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git diff --staged')) { + return Buffer.from('diff --git a/staged.ts b/staged.ts\n+staged change'); + } + if (command.includes('git rev-parse --abbrev-ref HEAD')) { + return Buffer.from('feature/test'); + } + return Buffer.from('test'); + }); + + const result = await analyzeTool.execute({ + staged: true, + cwd: tempDir, + }); + + expect(result.content[0].text).toContain('Static Analysis Results'); + expect(childProcess.execSync).toHaveBeenCalledWith( + 'git diff --staged', + expect.any(Object) + ); + }); + + it('should include DevOps cost estimates for infrastructure files', async () => { + // Mock diff with Terraform file + (childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git diff')) { + return Buffer.from(`diff --git a/main.tf b/main.tf ++resource "aws_instance" "web" { ++ ami = "ami-123456" ++ instance_type = "t3.medium" ++}`); + } + if (command.includes('git rev-parse --abbrev-ref HEAD')) { + return Buffer.from('feature/infra'); + } + return Buffer.from('test'); + }); + + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + verbose: true, + }); + + const text = result.content[0].text; + expect(text).toContain('DevOps Cost Estimates'); + }); + + it('should start dashboard in background', async () => { + await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + }); + + expect(mockDashboardService.startInBackground).toHaveBeenCalled(); + }); + + it('should handle custom PR title', async () => { + const customTitle = 'Custom PR Title'; + + const result = await analyzeTool.execute({ + branch: 'main', + title: customTitle, + cwd: tempDir, + verbose: true, + }); + + expect(result.content[0].text).toContain(customTitle); + }); + + it('should include verbose information when verbose flag is true', async () => { + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + verbose: true, + }); + + const text = result.content[0].text; + expect(text).toContain('PR Agent Analysis'); + expect(text).toContain('Repository:'); + expect(text).toContain('Branch:'); + }); + + it('should return prompts in PROMPT_ONLY mode', async () => { + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + }); + + const text = result.content[0].text; + expect(text).toContain('LLM Analysis Workflow'); + expect(text).toContain('prompts sequentially'); + }); + + it('should handle analysis errors gracefully', async () => { + // Mock git command to throw error + (childProcess.execSync as jest.Mock).mockImplementation(() => { + throw new Error('Git error'); + }); + + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + }); + + expect(result.content[0].text).toContain('Analysis failed'); + }); + + it('should extract ticket references from branch name', async () => { + (childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git rev-parse --abbrev-ref HEAD')) { + return Buffer.from('feature/TODO-123-implement-feature'); + } + if (command.includes('git diff')) { + return Buffer.from('diff --git a/file.ts b/file.ts\n+change'); + } + return Buffer.from('test'); + }); + + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + verbose: true, + }); + + // Analysis should complete successfully with ticket extraction + expect(result.content[0].text).toContain('Static Analysis Results'); + }); + + it('should disable archDocs when archDocs flag is false', async () => { + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + archDocs: false, + }); + + expect(result.content).toBeDefined(); + expect(result.content[0].text).toContain('Static Analysis Results'); + }); + + it('should use config default branch when no branch provided', async () => { + const configLoader = await import('../../../src/cli/utils/config-loader.js'); + (configLoader.loadUserConfig as any) = jest.fn(() => + Promise.resolve({ git: { defaultBranch: 'develop' } }) + ); + + await analyzeTool.execute({ + cwd: tempDir, + }); + + // Should use branch resolver which will use config + expect(configLoader.loadUserConfig).toHaveBeenCalled(); + }); + + it('should include next steps instructions', async () => { + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + }); + + const text = result.content[0].text; + expect(text).toContain('Next Steps'); + expect(text).toContain('saveAnalysisResults'); + }); + }); + + describe('Error Handling', () => { + it('should handle config loading errors gracefully', async () => { + const configLoader = await import('../../../src/cli/utils/config-loader.js'); + (configLoader.loadUserConfig as any) = jest.fn(() => + Promise.reject(new Error('Config error')) + ); + + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + }); + + // Should still work without config + expect(result.content).toBeDefined(); + }); + + it('should handle branch resolution errors gracefully', async () => { + const branchResolver = await import('../../../src/utils/branch-resolver.js'); + (branchResolver.resolveDefaultBranch as any) = jest.fn(() => + Promise.reject(new Error('Branch error')) + ); + + const result = await analyzeTool.execute({ + cwd: tempDir, + }); + + // Should fallback to default branch + expect(result.content).toBeDefined(); + }); + + it('should handle repo info extraction errors', async () => { + (childProcess.execSync as jest.Mock).mockImplementation((cmd: any) => { + const command = String(cmd); + if (command.includes('git remote get-url origin')) { + throw new Error('No remote'); + } + if (command.includes('git diff')) { + return Buffer.from('diff --git a/file.ts b/file.ts\n+change'); + } + return Buffer.from('test'); + }); + + const result = await analyzeTool.execute({ + branch: 'main', + cwd: tempDir, + }); + + // Should use 'local' for repo owner + expect(result.content).toBeDefined(); + }); + }); +}); diff --git a/tests/mcp/tools/save-results-tool.integration.test.ts b/tests/mcp/tools/save-results-tool.integration.test.ts new file mode 100644 index 0000000..7dd7cad --- /dev/null +++ b/tests/mcp/tools/save-results-tool.integration.test.ts @@ -0,0 +1,342 @@ +/** + * Integration tests for SaveResultsTool + * Tests database operations for saving analysis results + */ + +import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals'; +import { SaveResultsTool } from '../../../src/mcp/tools/save-results-tool.js'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; + +describe('SaveResultsTool Integration Tests', () => { + let saveResultsTool: SaveResultsTool; + let tempDir: string; + let dbPath: string; + + beforeEach(() => { + // Create temp directory for test database + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pr-agent-save-test-')); + dbPath = path.join(tempDir, 'test.db'); + + // Set environment variable to use test database + process.env.PR_AGENT_DB_PATH = dbPath; + + saveResultsTool = new SaveResultsTool(); + }); + + afterEach(() => { + try { + if (fs.existsSync(tempDir)) { + setTimeout(() => { + try { + fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); + } catch { + // Ignore cleanup errors + } + }, 100); + } + } catch { + // Ignore cleanup errors + } + delete process.env.PR_AGENT_DB_PATH; + }); + + describe('execute', () => { + it('should save basic analysis results successfully', async () => { + const args = { + title: 'Test PR', + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 3, + risksCount: 2, + risks: ['Risk 1', 'Risk 2'], + recommendations: ['Recommendation 1', 'Recommendation 2'], + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content).toBeDefined(); + expect(result.content[0].type).toBe('text'); + expect(result.content[0].text).toContain('Analysis results saved to database'); + expect(result.content[0].text).toContain('View results at: http://localhost:3000'); + }); + + it('should save results with peer review data', async () => { + const args = { + title: 'Test PR with Peer Review', + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 2, + risksCount: 1, + risks: ['Minor risk'], + recommendations: ['Improve tests'], + peerReviewEnabled: true, + ticketKey: 'TODO-123', + ticketQualityScore: 85, + ticketQualityTier: 'A', + acCompliancePercentage: 90, + acRequirementsTotal: 10, + acRequirementsMet: 9, + peerReviewVerdict: 'approve' as const, + peerReviewWarnings: ['Minor warning'], + peerReviewBlockers: [], + implementationCompleteness: 95, + qualityScore: 88, + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content[0].text).toContain('Analysis results saved'); + }); + + it('should save results with DevOps cost data', async () => { + const args = { + title: 'Infrastructure PR', + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 4, + risksCount: 3, + risks: ['Cost overrun', 'Security', 'Availability'], + recommendations: ['Review costs', 'Add monitoring'], + devopsCostMonthly: 156.75, + devopsResources: JSON.stringify([ + { type: 'ec2', cost: 34.5 }, + { type: 'rds', cost: 60 }, + { type: 'alb', cost: 22.5 }, + ]), + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content[0].text).toContain('Analysis results saved'); + }); + + it('should save results with project classification', async () => { + const args = { + title: 'Feature PR', + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 2, + risksCount: 0, + risks: [], + recommendations: ['Add tests'], + projectClassification: JSON.stringify({ + type: 'business-logic', + confidence: 95, + indicators: ['React components', 'API calls'], + }), + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content[0].text).toContain('Analysis results saved'); + }); + + it('should handle empty risks and recommendations', async () => { + const args = { + title: 'Simple PR', + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 1, + risksCount: 0, + risks: [], + recommendations: [], + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content[0].text).toContain('Analysis results saved'); + }); + + it('should handle PR number', async () => { + const args = { + title: 'PR #42', + repoOwner: 'test-owner', + repoName: 'test-repo', + prNumber: 42, + complexity: 2, + risksCount: 1, + risks: ['Risk'], + recommendations: ['Rec'], + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content[0].text).toContain('Analysis results saved'); + }); + + it('should handle author information', async () => { + const args = { + title: 'Author PR', + repoOwner: 'test-owner', + repoName: 'test-repo', + author: 'john-doe', + complexity: 2, + risksCount: 0, + risks: [], + recommendations: [], + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content[0].text).toContain('Analysis results saved'); + }); + + it('should handle all peer review verdict types', async () => { + const verdicts: Array<'approve' | 'request_changes' | 'needs_discussion'> = [ + 'approve', + 'request_changes', + 'needs_discussion', + ]; + + for (const verdict of verdicts) { + const args = { + title: `PR with ${verdict}`, + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 2, + risksCount: 1, + risks: ['Risk'], + recommendations: ['Rec'], + peerReviewEnabled: true, + peerReviewVerdict: verdict, + }; + + const result = await saveResultsTool.execute(args); + expect(result.content[0].text).toContain('Analysis results saved'); + } + }); + + it('should handle error when database operations fail', async () => { + // Use invalid database path to trigger error + process.env.PR_AGENT_DB_PATH = '/invalid/path/db.sqlite'; + + const args = { + title: 'Test PR', + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 2, + risksCount: 0, + risks: [], + recommendations: [], + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content[0].text).toContain('Failed to save analysis results'); + }); + + it('should validate required fields', async () => { + const args = { + title: 'Test', + repoOwner: 'owner', + repoName: 'repo', + // Missing required fields + } as any; + + const result = await saveResultsTool.execute(args); + + // Should either handle gracefully or include error message + expect(result.content).toBeDefined(); + }); + + it('should handle very long text fields', async () => { + const longText = 'A'.repeat(10000); + const args = { + title: longText, + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 3, + risksCount: 1, + risks: [longText], + recommendations: [longText], + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content[0].text).toContain('Analysis results saved'); + }); + + it('should handle special characters in text fields', async () => { + const args = { + title: 'Test "quotes" & and \' apostrophes', + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 2, + risksCount: 1, + risks: ['Risk with "quotes"'], + recommendations: ['Rec with '], + }; + + const result = await saveResultsTool.execute(args); + + expect(result.content[0].text).toContain('Analysis results saved'); + }); + + it('should handle multiple saves to same database', async () => { + const createArgs = (id: number) => ({ + title: `PR ${id}`, + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: id % 5 + 1, + risksCount: id % 3, + risks: Array(id % 3).fill(`Risk ${id}`), + recommendations: [`Recommendation ${id}`], + }); + + // Save multiple results + for (let i = 1; i <= 5; i++) { + const result = await saveResultsTool.execute(createArgs(i)); + expect(result.content[0].text).toContain('Analysis results saved'); + } + }); + }); + + describe('Database Schema Validation', () => { + it('should create database with correct schema', async () => { + const args = { + title: 'Test PR', + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 2, + risksCount: 0, + risks: [], + recommendations: [], + }; + + await saveResultsTool.execute(args); + + // Database file should exist + expect(fs.existsSync(dbPath)).toBe(true); + }); + + it('should handle concurrent saves', async () => { + const args = { + title: 'Concurrent PR', + repoOwner: 'test-owner', + repoName: 'test-repo', + complexity: 2, + risksCount: 1, + risks: ['Risk'], + recommendations: ['Rec'], + }; + + // Attempt concurrent saves + const promises = Array(3) + .fill(null) + .map((_, i) => + saveResultsTool.execute({ + ...args, + title: `${args.title} ${i}`, + }) + ); + + const results = await Promise.all(promises); + + results.forEach((result) => { + expect(result.content[0].text).toContain('Analysis results saved'); + }); + }); + }); +}); diff --git a/tests/tools/devops-cost-estimator.test.ts b/tests/tools/devops-cost-estimator.test.ts new file mode 100644 index 0000000..82ad9fc --- /dev/null +++ b/tests/tools/devops-cost-estimator.test.ts @@ -0,0 +1,422 @@ +/** + * Unit tests for DevOps Cost Estimator + * Tests infrastructure cost estimation for IaC files + */ + +import { describe, it, expect, beforeEach } from '@jest/globals'; +import { + isDevOpsFile, + analyzeDevOpsFiles, + formatCostEstimates, +} from '../../src/tools/devops-cost-estimator.js'; + +describe('DevOps Cost Estimator', () => { + describe('isDevOpsFile', () => { + it('should detect Terraform files', () => { + expect(isDevOpsFile('main.tf')).toEqual({ isDevOps: true, type: 'terraform' }); + expect(isDevOpsFile('variables.tfvars')).toEqual({ isDevOps: true, type: 'terraform' }); + expect(isDevOpsFile('infrastructure/aws.tf')).toEqual({ isDevOps: true, type: 'terraform' }); + }); + + it('should detect CloudFormation files', () => { + expect(isDevOpsFile('template.yaml')).toEqual({ isDevOps: true, type: 'cloudformation' }); + expect(isDevOpsFile('cloudformation.json')).toEqual({ isDevOps: true, type: 'cloudformation' }); + }); + + it('should detect Dockerfile', () => { + expect(isDevOpsFile('Dockerfile')).toEqual({ isDevOps: true, type: 'docker' }); + expect(isDevOpsFile('docker-compose.yml')).toEqual({ isDevOps: true, type: 'docker' }); + }); + + it('should detect Kubernetes files', () => { + expect(isDevOpsFile('k8s-deployment.yaml')).toEqual({ isDevOps: true, type: 'kubernetes' }); + expect(isDevOpsFile('kubernetes/service.yml')).toEqual({ isDevOps: true, type: 'kubernetes' }); + }); + + it('should detect GitHub Actions workflows', () => { + expect(isDevOpsFile('.github/workflows/deploy.yml')).toEqual({ + isDevOps: true, + type: 'github_actions', + }); + }); + + it('should detect serverless config', () => { + expect(isDevOpsFile('serverless.yml')).toEqual({ isDevOps: true, type: 'serverless' }); + }); + + it('should return false for non-DevOps files', () => { + expect(isDevOpsFile('src/index.ts')).toEqual({ isDevOps: false, type: null }); + expect(isDevOpsFile('README.md')).toEqual({ isDevOps: false, type: null }); + expect(isDevOpsFile('package.json')).toEqual({ isDevOps: false, type: null }); + }); + }); + + describe('analyzeDevOpsFiles', () => { + it('should return no changes for empty file list', () => { + const result = analyzeDevOpsFiles([]); + + expect(result).toEqual({ + hasDevOpsChanges: false, + fileTypes: [], + estimates: [], + totalEstimatedCost: 0, + }); + }); + + it('should return no changes for non-DevOps files', () => { + const files = [ + { path: 'src/index.ts', diff: 'export const foo = "bar";' }, + { path: 'README.md', diff: '# Title' }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result).toEqual({ + hasDevOpsChanges: false, + fileTypes: [], + estimates: [], + totalEstimatedCost: 0, + }); + }); + + it('should detect Terraform EC2 resources', () => { + const files = [ + { + path: 'main.tf', + diff: ` ++resource "aws_instance" "web" { ++ ami = "ami-123456" ++ instance_type = "t3.medium" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.hasDevOpsChanges).toBe(true); + expect(result.fileTypes).toContain('terraform'); + expect(result.estimates.length).toBeGreaterThan(0); + expect(result.estimates[0].resourceType).toBe('ec2'); + expect(result.estimates[0].estimatedNewCost).toBeGreaterThan(0); + }); + + it('should detect Terraform Lambda resources', () => { + const files = [ + { + path: 'lambda.tf', + diff: ` ++resource "aws_lambda_function" "api" { ++ function_name = "my-function" ++ handler = "index.handler" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.hasDevOpsChanges).toBe(true); + expect(result.estimates.some((e) => e.resourceType === 'lambda')).toBe(true); + }); + + it('should detect Terraform RDS resources', () => { + const files = [ + { + path: 'database.tf', + diff: ` ++resource "aws_db_instance" "postgres" { ++ engine = "postgres" ++ instance_class = "db.t3.small" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.hasDevOpsChanges).toBe(true); + expect(result.estimates.some((e) => e.resourceType === 'rds')).toBe(true); + }); + + it('should detect Terraform S3 resources', () => { + const files = [ + { + path: 'storage.tf', + diff: ` ++resource "aws_s3_bucket" "uploads" { ++ bucket = "my-uploads" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.hasDevOpsChanges).toBe(true); + expect(result.estimates.some((e) => e.resourceType === 's3')).toBe(true); + }); + + it('should detect Terraform ECS resources', () => { + const files = [ + { + path: 'ecs.tf', + diff: ` ++resource "aws_ecs_cluster" "main" { ++ name = "app-cluster" ++} ++resource "aws_ecs_service" "app" { ++ name = "app-service" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.hasDevOpsChanges).toBe(true); + expect(result.estimates.some((e) => e.resourceType === 'ecs')).toBe(true); + }); + + it('should detect Terraform ALB resources', () => { + const files = [ + { + path: 'lb.tf', + diff: ` ++resource "aws_lb" "main" { ++ name = "app-lb" ++ load_balancer_type = "application" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.hasDevOpsChanges).toBe(true); + expect(result.estimates.some((e) => e.resourceType === 'alb')).toBe(true); + }); + + it('should calculate total cost for multiple resources', () => { + const files = [ + { + path: 'main.tf', + diff: ` ++resource "aws_instance" "web" { ++ instance_type = "t3.medium" ++} ++resource "aws_db_instance" "postgres" { ++ instance_class = "db.t3.small" ++} ++resource "aws_lb" "main" { ++ load_balancer_type = "application" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.hasDevOpsChanges).toBe(true); + expect(result.estimates.length).toBeGreaterThanOrEqual(3); + expect(result.totalEstimatedCost).toBeGreaterThan(0); + + // Should be sum of individual estimates + const calculatedTotal = result.estimates.reduce( + (sum, e) => sum + e.estimatedNewCost, + 0 + ); + expect(result.totalEstimatedCost).toBeCloseTo(calculatedTotal, 2); + }); + + it('should deduplicate resource types', () => { + const files = [ + { + path: 'main.tf', + diff: ` ++resource "aws_instance" "web1" { ++ instance_type = "t3.medium" ++} ++resource "aws_instance" "web2" { ++ instance_type = "t3.medium" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + // Should only estimate once per resource type + const ec2Estimates = result.estimates.filter((e) => e.resourceType === 'ec2'); + expect(ec2Estimates.length).toBe(1); + }); + + it('should handle CloudFormation resources', () => { + const files = [ + { + path: 'template.yaml', + diff: ` +Resources: + MyInstance: + Type: AWS::EC2::Instance + Properties: + InstanceType: t3.medium + MyBucket: + Type: AWS::S3::Bucket`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.hasDevOpsChanges).toBe(true); + expect(result.fileTypes).toContain('cloudformation'); + expect(result.estimates.length).toBeGreaterThan(0); + }); + + it('should set confidence levels appropriately', () => { + const files = [ + { + path: 'main.tf', + diff: ` ++resource "aws_lb" "main" { ++ load_balancer_type = "application" ++} ++resource "aws_lambda_function" "api" { ++ function_name = "my-function" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + // ALB should have high confidence (fixed cost) + const albEstimate = result.estimates.find((e) => e.resourceType === 'alb'); + expect(albEstimate?.confidence).toBe('high'); + + // Lambda should have low confidence (usage-based) + const lambdaEstimate = result.estimates.find((e) => e.resourceType === 'lambda'); + expect(lambdaEstimate?.confidence).toBe('low'); + }); + + it('should include cost details', () => { + const files = [ + { + path: 'main.tf', + diff: '+resource "aws_instance" "web" { instance_type = "t3.medium" }', + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.estimates[0].details).toBeDefined(); + expect(result.estimates[0].details).toContain('$'); + expect(result.estimates[0].details).toContain('month'); + }); + + it('should handle diff format with + prefix correctly', () => { + const files = [ + { + path: 'main.tf', + diff: `diff --git a/main.tf b/main.tf +index 123..456 +--- a/main.tf ++++ b/main.tf +@@ -1,0 +1,5 @@ ++resource "aws_instance" "web" { ++ ami = "ami-123" ++ instance_type = "t3.medium" ++}`, + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.hasDevOpsChanges).toBe(true); + expect(result.estimates.some((e) => e.resourceType === 'ec2')).toBe(true); + }); + + it('should handle multiple file types', () => { + const files = [ + { + path: 'main.tf', + diff: '+resource "aws_instance" "web" {}', + }, + { + path: 'template.yaml', + diff: 'Type: AWS::Lambda::Function', + }, + ]; + + const result = analyzeDevOpsFiles(files); + + expect(result.fileTypes).toContain('terraform'); + expect(result.fileTypes).toContain('cloudformation'); + }); + }); + + describe('formatCostEstimates', () => { + it('should format empty estimates', () => { + const formatted = formatCostEstimates([], 0); + + expect(formatted).toContain('No cost estimates available'); + }); + + it('should format single estimate', () => { + const estimates = [ + { + resource: 'test-alb', + resourceType: 'alb', + estimatedNewCost: 22.5, + confidence: 'high' as const, + details: 'Estimated $16-30/month', + }, + ]; + + const formatted = formatCostEstimates(estimates, 22.5); + + expect(formatted).toContain('AWS Cost Estimates'); + expect(formatted).toContain('alb'); + expect(formatted).toContain('$22.50/month'); + expect(formatted).toContain('Total Estimated Impact: ~$22.50/month'); + expect(formatted).toContain('🟢'); // high confidence + }); + + it('should format multiple estimates with different confidence levels', () => { + const estimates = [ + { + resource: 'alb', + resourceType: 'alb', + estimatedNewCost: 22, + confidence: 'high' as const, + }, + { + resource: 'ec2', + resourceType: 'ec2', + estimatedNewCost: 34, + confidence: 'medium' as const, + }, + { + resource: 'lambda', + resourceType: 'lambda', + estimatedNewCost: 0.4, + confidence: 'low' as const, + }, + ]; + + const formatted = formatCostEstimates(estimates, 56.4); + + expect(formatted).toContain('🟢'); // high + expect(formatted).toContain('🟡'); // medium + expect(formatted).toContain('🔴'); // low + expect(formatted).toContain('$56.40/month'); + }); + + it('should include disclaimer', () => { + const estimates = [ + { + resource: 'test', + resourceType: 'ec2', + estimatedNewCost: 10, + confidence: 'medium' as const, + }, + ]; + + const formatted = formatCostEstimates(estimates, 10); + + expect(formatted).toContain('Estimates are approximate'); + expect(formatted).toContain('Actual costs depend on usage and configuration'); + }); + }); +});